mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-21 06:51:01 +00:00
refactor: untangle whatsapp runtime boundary
This commit is contained in:
@@ -22,18 +22,22 @@ describe("bundled plugin runtime dependencies", () => {
|
||||
expect(rootSpec).toBeUndefined();
|
||||
}
|
||||
|
||||
function expectRootMirrorsPluginRuntimeDep(pluginPath: string, dependencyName: string) {
|
||||
const rootManifest = readJson<PackageManifest>("package.json");
|
||||
const pluginManifest = readJson<PackageManifest>(pluginPath);
|
||||
const pluginSpec = pluginManifest.dependencies?.[dependencyName];
|
||||
const rootSpec = rootManifest.dependencies?.[dependencyName];
|
||||
|
||||
expect(pluginSpec).toBeTruthy();
|
||||
expect(rootSpec).toBe(pluginSpec);
|
||||
}
|
||||
|
||||
it("keeps bundled Feishu runtime deps plugin-local instead of mirroring them into the root package", () => {
|
||||
expectPluginOwnsRuntimeDep("extensions/feishu/package.json", "@larksuiteoapi/node-sdk");
|
||||
});
|
||||
|
||||
it("keeps bundled memory-lancedb runtime deps available from the root package while its native runtime stays bundled", () => {
|
||||
const rootManifest = readJson<PackageManifest>("package.json");
|
||||
const memoryManifest = readJson<PackageManifest>("extensions/memory-lancedb/package.json");
|
||||
const memorySpec = memoryManifest.dependencies?.["@lancedb/lancedb"];
|
||||
const rootSpec = rootManifest.dependencies?.["@lancedb/lancedb"];
|
||||
|
||||
expect(memorySpec).toBeTruthy();
|
||||
expect(rootSpec).toBe(memorySpec);
|
||||
it("keeps bundled memory-lancedb runtime deps mirrored in the root package while its native runtime is still packaged that way", () => {
|
||||
expectRootMirrorsPluginRuntimeDep("extensions/memory-lancedb/package.json", "@lancedb/lancedb");
|
||||
});
|
||||
|
||||
it("keeps bundled Discord runtime deps plugin-local instead of mirroring them into the root package", () => {
|
||||
@@ -48,6 +52,13 @@ describe("bundled plugin runtime dependencies", () => {
|
||||
expectPluginOwnsRuntimeDep("extensions/telegram/package.json", "grammy");
|
||||
});
|
||||
|
||||
it("keeps bundled WhatsApp runtime deps mirrored in the root package while its heavy runtime still uses the legacy bundle path", () => {
|
||||
expectRootMirrorsPluginRuntimeDep(
|
||||
"extensions/whatsapp/package.json",
|
||||
"@whiskeysockets/baileys",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps bundled proxy-agent deps plugin-local instead of mirroring them into the root package", () => {
|
||||
expectPluginOwnsRuntimeDep("extensions/discord/package.json", "https-proxy-agent");
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ import { isChannelConfigured } from "../config/plugin-auto-enable.js";
|
||||
import type { PluginInstallRecord } from "../config/types.plugins.js";
|
||||
import type { GatewayRequestHandler } from "../gateway/server-methods/types.js";
|
||||
import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
|
||||
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { inspectBundleMcpRuntimeSupport } from "./bundle-mcp.js";
|
||||
@@ -31,6 +30,17 @@ import { setActivePluginRegistry } from "./runtime.js";
|
||||
import type { CreatePluginRuntimeOptions } from "./runtime/index.js";
|
||||
import type { PluginRuntime } from "./runtime/types.js";
|
||||
import { validateJsonSchemaValue } from "./schema-validator.js";
|
||||
import {
|
||||
buildPluginLoaderJitiOptions,
|
||||
listPluginSdkAliasCandidates,
|
||||
listPluginSdkExportedSubpaths,
|
||||
resolveLoaderPackageRoot,
|
||||
resolvePluginSdkAliasCandidateOrder,
|
||||
resolvePluginSdkAliasFile,
|
||||
resolvePluginSdkScopedAliasMap,
|
||||
shouldPreferNativeJiti,
|
||||
type LoaderModuleResolveParams,
|
||||
} from "./sdk-alias.js";
|
||||
import type {
|
||||
OpenClawPluginDefinition,
|
||||
OpenClawPluginModule,
|
||||
@@ -90,130 +100,13 @@ export function clearPluginLoaderCache(): void {
|
||||
|
||||
const defaultLogger = () => createSubsystemLogger("plugins");
|
||||
|
||||
type PluginSdkAliasCandidateKind = "dist" | "src";
|
||||
|
||||
type LoaderModuleResolveParams = {
|
||||
modulePath?: string;
|
||||
argv1?: string;
|
||||
cwd?: string;
|
||||
moduleUrl?: string;
|
||||
};
|
||||
|
||||
function resolveLoaderModulePath(params: LoaderModuleResolveParams = {}): string {
|
||||
return params.modulePath ?? fileURLToPath(params.moduleUrl ?? import.meta.url);
|
||||
}
|
||||
|
||||
function resolveLoaderPackageRoot(
|
||||
params: LoaderModuleResolveParams & { modulePath: string },
|
||||
): string | null {
|
||||
const cwd = params.cwd ?? path.dirname(params.modulePath);
|
||||
const fromModulePath = resolveOpenClawPackageRootSync({ cwd });
|
||||
if (fromModulePath) {
|
||||
return fromModulePath;
|
||||
}
|
||||
const argv1 = params.argv1 ?? process.argv[1];
|
||||
const moduleUrl = params.moduleUrl ?? (params.modulePath ? undefined : import.meta.url);
|
||||
return resolveOpenClawPackageRootSync({
|
||||
cwd,
|
||||
...(argv1 ? { argv1 } : {}),
|
||||
...(moduleUrl ? { moduleUrl } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
function resolvePluginSdkAliasCandidateOrder(params: {
|
||||
modulePath: string;
|
||||
isProduction: boolean;
|
||||
}): PluginSdkAliasCandidateKind[] {
|
||||
const normalizedModulePath = params.modulePath.replace(/\\/g, "/");
|
||||
const isDistRuntime = normalizedModulePath.includes("/dist/");
|
||||
return isDistRuntime || params.isProduction ? ["dist", "src"] : ["src", "dist"];
|
||||
}
|
||||
|
||||
function listPluginSdkAliasCandidates(params: {
|
||||
srcFile: string;
|
||||
distFile: string;
|
||||
modulePath: string;
|
||||
argv1?: string;
|
||||
cwd?: string;
|
||||
moduleUrl?: string;
|
||||
}) {
|
||||
const orderedKinds = resolvePluginSdkAliasCandidateOrder({
|
||||
modulePath: params.modulePath,
|
||||
isProduction: process.env.NODE_ENV === "production",
|
||||
});
|
||||
const packageRoot = resolveLoaderPackageRoot(params);
|
||||
if (packageRoot) {
|
||||
const candidateMap = {
|
||||
src: path.join(packageRoot, "src", "plugin-sdk", params.srcFile),
|
||||
dist: path.join(packageRoot, "dist", "plugin-sdk", params.distFile),
|
||||
} as const;
|
||||
return orderedKinds.map((kind) => candidateMap[kind]);
|
||||
}
|
||||
let cursor = path.dirname(params.modulePath);
|
||||
const candidates: string[] = [];
|
||||
for (let i = 0; i < 6; i += 1) {
|
||||
const candidateMap = {
|
||||
src: path.join(cursor, "src", "plugin-sdk", params.srcFile),
|
||||
dist: path.join(cursor, "dist", "plugin-sdk", params.distFile),
|
||||
} as const;
|
||||
for (const kind of orderedKinds) {
|
||||
candidates.push(candidateMap[kind]);
|
||||
}
|
||||
const parent = path.dirname(cursor);
|
||||
if (parent === cursor) {
|
||||
break;
|
||||
}
|
||||
cursor = parent;
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
const resolvePluginSdkAliasFile = (params: {
|
||||
srcFile: string;
|
||||
distFile: string;
|
||||
modulePath?: string;
|
||||
argv1?: string;
|
||||
cwd?: string;
|
||||
moduleUrl?: string;
|
||||
}): string | null => {
|
||||
try {
|
||||
const modulePath = resolveLoaderModulePath(params);
|
||||
for (const candidate of listPluginSdkAliasCandidates({
|
||||
srcFile: params.srcFile,
|
||||
distFile: params.distFile,
|
||||
modulePath,
|
||||
argv1: params.argv1,
|
||||
cwd: params.cwd,
|
||||
moduleUrl: params.moduleUrl,
|
||||
})) {
|
||||
if (fs.existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const resolvePluginSdkAlias = (): string | null =>
|
||||
resolvePluginSdkAliasFile({ srcFile: "root-alias.cjs", distFile: "root-alias.cjs" });
|
||||
|
||||
function buildPluginLoaderJitiOptions(aliasMap: Record<string, string>) {
|
||||
return {
|
||||
interopDefault: true,
|
||||
// Prefer Node's native sync ESM loader for built dist/*.js modules so
|
||||
// bundled plugins and plugin-sdk subpaths stay on the canonical module graph.
|
||||
tryNative: true,
|
||||
extensions: [".ts", ".tsx", ".mts", ".cts", ".mtsx", ".ctsx", ".js", ".mjs", ".cjs", ".json"],
|
||||
...(Object.keys(aliasMap).length > 0
|
||||
? {
|
||||
alias: aliasMap,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
function resolvePluginRuntimeModulePath(params: LoaderModuleResolveParams = {}): string | null {
|
||||
try {
|
||||
const modulePath = resolveLoaderModulePath(params);
|
||||
@@ -243,63 +136,6 @@ function resolvePluginRuntimeModulePath(params: LoaderModuleResolveParams = {}):
|
||||
return null;
|
||||
}
|
||||
|
||||
const cachedPluginSdkExportedSubpaths = new Map<string, string[]>();
|
||||
|
||||
function listPluginSdkExportedSubpaths(params: { modulePath?: string } = {}): string[] {
|
||||
const modulePath = params.modulePath ?? fileURLToPath(import.meta.url);
|
||||
const packageRoot = resolveOpenClawPackageRootSync({
|
||||
cwd: path.dirname(modulePath),
|
||||
});
|
||||
if (!packageRoot) {
|
||||
return [];
|
||||
}
|
||||
const cached = cachedPluginSdkExportedSubpaths.get(packageRoot);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
try {
|
||||
const pkgRaw = fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8");
|
||||
const pkg = JSON.parse(pkgRaw) as {
|
||||
exports?: Record<string, unknown>;
|
||||
};
|
||||
const subpaths = Object.keys(pkg.exports ?? {})
|
||||
.filter((key) => key.startsWith("./plugin-sdk/"))
|
||||
.map((key) => key.slice("./plugin-sdk/".length))
|
||||
.filter((subpath) => Boolean(subpath) && !subpath.includes("/"))
|
||||
.toSorted();
|
||||
cachedPluginSdkExportedSubpaths.set(packageRoot, subpaths);
|
||||
return subpaths;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const resolvePluginSdkScopedAliasMap = (): Record<string, string> => {
|
||||
const aliasMap: Record<string, string> = {};
|
||||
for (const subpath of listPluginSdkExportedSubpaths()) {
|
||||
const resolved = resolvePluginSdkAliasFile({
|
||||
srcFile: `${subpath}.ts`,
|
||||
distFile: `${subpath}.js`,
|
||||
});
|
||||
if (resolved) {
|
||||
aliasMap[`openclaw/plugin-sdk/${subpath}`] = resolved;
|
||||
}
|
||||
}
|
||||
return aliasMap;
|
||||
};
|
||||
|
||||
function shouldPreferNativeJiti(modulePath: string): boolean {
|
||||
switch (path.extname(modulePath).toLowerCase()) {
|
||||
case ".js":
|
||||
case ".mjs":
|
||||
case ".cjs":
|
||||
case ".json":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
buildPluginLoaderJitiOptions,
|
||||
listPluginSdkAliasCandidates,
|
||||
|
||||
339
src/plugins/runtime/runtime-whatsapp-boundary.ts
Normal file
339
src/plugins/runtime/runtime-whatsapp-boundary.ts
Normal file
@@ -0,0 +1,339 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { createJiti } from "jiti";
|
||||
import { resolveWhatsAppHeartbeatRecipients } from "../../channels/plugins/whatsapp-heartbeat.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import {
|
||||
getDefaultLocalRoots as getDefaultLocalRootsImpl,
|
||||
loadWebMedia as loadWebMediaImpl,
|
||||
loadWebMediaRaw as loadWebMediaRawImpl,
|
||||
optimizeImageToJpeg as optimizeImageToJpegImpl,
|
||||
} from "../../media/web-media.js";
|
||||
import { loadPluginManifestRegistry } from "../manifest-registry.js";
|
||||
import {
|
||||
buildPluginLoaderJitiOptions,
|
||||
resolvePluginSdkAliasFile,
|
||||
resolvePluginSdkScopedAliasMap,
|
||||
shouldPreferNativeJiti,
|
||||
} from "../sdk-alias.js";
|
||||
|
||||
const WHATSAPP_PLUGIN_ID = "whatsapp";
|
||||
|
||||
type WhatsAppLightModule = typeof import("../../../extensions/whatsapp/light-runtime-api.js");
|
||||
type WhatsAppHeavyModule = typeof import("../../../extensions/whatsapp/runtime-api.js");
|
||||
|
||||
type WhatsAppPluginRecord = {
|
||||
origin: string;
|
||||
rootDir?: string;
|
||||
source: string;
|
||||
};
|
||||
|
||||
let cachedHeavyModulePath: string | null = null;
|
||||
let cachedHeavyModule: WhatsAppHeavyModule | null = null;
|
||||
let cachedLightModulePath: string | null = null;
|
||||
let cachedLightModule: WhatsAppLightModule | null = null;
|
||||
|
||||
const jitiLoaders = new Map<boolean, ReturnType<typeof createJiti>>();
|
||||
|
||||
function readConfigSafely() {
|
||||
try {
|
||||
return loadConfig();
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function resolveWhatsAppPluginRecord(): WhatsAppPluginRecord {
|
||||
const manifestRegistry = loadPluginManifestRegistry({
|
||||
config: readConfigSafely(),
|
||||
cache: true,
|
||||
});
|
||||
const record = manifestRegistry.plugins.find((plugin) => plugin.id === WHATSAPP_PLUGIN_ID);
|
||||
if (!record?.source) {
|
||||
throw new Error(
|
||||
`WhatsApp plugin runtime is unavailable: missing plugin '${WHATSAPP_PLUGIN_ID}'`,
|
||||
);
|
||||
}
|
||||
return {
|
||||
origin: record.origin,
|
||||
rootDir: record.rootDir,
|
||||
source: record.source,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveWhatsAppRuntimeModulePath(
|
||||
record: WhatsAppPluginRecord,
|
||||
entryBaseName: "light-runtime-api" | "runtime-api",
|
||||
): string {
|
||||
const candidates = [
|
||||
path.join(path.dirname(record.source), `${entryBaseName}.js`),
|
||||
path.join(path.dirname(record.source), `${entryBaseName}.ts`),
|
||||
...(record.rootDir
|
||||
? [
|
||||
path.join(record.rootDir, `${entryBaseName}.js`),
|
||||
path.join(record.rootDir, `${entryBaseName}.ts`),
|
||||
]
|
||||
: []),
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
if (fs.existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`WhatsApp plugin runtime is unavailable: missing ${entryBaseName} for plugin '${WHATSAPP_PLUGIN_ID}'`,
|
||||
);
|
||||
}
|
||||
|
||||
function getJiti(modulePath: string) {
|
||||
const tryNative = shouldPreferNativeJiti(modulePath);
|
||||
const cached = jitiLoaders.get(tryNative);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const pluginSdkAlias = resolvePluginSdkAliasFile({
|
||||
srcFile: "root-alias.cjs",
|
||||
distFile: "root-alias.cjs",
|
||||
modulePath: modulePath,
|
||||
});
|
||||
const aliasMap = {
|
||||
...(pluginSdkAlias ? { "openclaw/plugin-sdk": pluginSdkAlias } : {}),
|
||||
...resolvePluginSdkScopedAliasMap({ modulePath }),
|
||||
};
|
||||
const loader = createJiti(import.meta.url, {
|
||||
...buildPluginLoaderJitiOptions(aliasMap),
|
||||
tryNative,
|
||||
});
|
||||
jitiLoaders.set(tryNative, loader);
|
||||
return loader;
|
||||
}
|
||||
|
||||
function loadWithJiti<TModule>(modulePath: string): TModule {
|
||||
return getJiti(modulePath)(modulePath) as TModule;
|
||||
}
|
||||
|
||||
function loadCurrentHeavyModuleSync(): WhatsAppHeavyModule {
|
||||
const modulePath = resolveWhatsAppRuntimeModulePath(resolveWhatsAppPluginRecord(), "runtime-api");
|
||||
return loadWithJiti<WhatsAppHeavyModule>(modulePath);
|
||||
}
|
||||
|
||||
function loadWhatsAppLightModule(): WhatsAppLightModule {
|
||||
const modulePath = resolveWhatsAppRuntimeModulePath(
|
||||
resolveWhatsAppPluginRecord(),
|
||||
"light-runtime-api",
|
||||
);
|
||||
if (cachedLightModule && cachedLightModulePath === modulePath) {
|
||||
return cachedLightModule;
|
||||
}
|
||||
const loaded = loadWithJiti<WhatsAppLightModule>(modulePath);
|
||||
cachedLightModulePath = modulePath;
|
||||
cachedLightModule = loaded;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
async function loadWhatsAppHeavyModule(): Promise<WhatsAppHeavyModule> {
|
||||
const record = resolveWhatsAppPluginRecord();
|
||||
const modulePath = resolveWhatsAppRuntimeModulePath(record, "runtime-api");
|
||||
if (cachedHeavyModule && cachedHeavyModulePath === modulePath) {
|
||||
return cachedHeavyModule;
|
||||
}
|
||||
const loaded = loadWithJiti<WhatsAppHeavyModule>(modulePath);
|
||||
cachedHeavyModulePath = modulePath;
|
||||
cachedHeavyModule = loaded;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
function getLightExport<K extends keyof WhatsAppLightModule>(
|
||||
exportName: K,
|
||||
): NonNullable<WhatsAppLightModule[K]> {
|
||||
const loaded = loadWhatsAppLightModule();
|
||||
const value = loaded[exportName];
|
||||
if (value == null) {
|
||||
throw new Error(`WhatsApp plugin runtime is missing export '${String(exportName)}'`);
|
||||
}
|
||||
return value as NonNullable<WhatsAppLightModule[K]>;
|
||||
}
|
||||
|
||||
async function getHeavyExport<K extends keyof WhatsAppHeavyModule>(
|
||||
exportName: K,
|
||||
): Promise<NonNullable<WhatsAppHeavyModule[K]>> {
|
||||
const loaded = await loadWhatsAppHeavyModule();
|
||||
const value = loaded[exportName];
|
||||
if (value == null) {
|
||||
throw new Error(`WhatsApp plugin runtime is missing export '${String(exportName)}'`);
|
||||
}
|
||||
return value as NonNullable<WhatsAppHeavyModule[K]>;
|
||||
}
|
||||
|
||||
export function getActiveWebListener(
|
||||
...args: Parameters<WhatsAppLightModule["getActiveWebListener"]>
|
||||
): ReturnType<WhatsAppLightModule["getActiveWebListener"]> {
|
||||
return getLightExport("getActiveWebListener")(...args);
|
||||
}
|
||||
|
||||
export function getWebAuthAgeMs(
|
||||
...args: Parameters<WhatsAppLightModule["getWebAuthAgeMs"]>
|
||||
): ReturnType<WhatsAppLightModule["getWebAuthAgeMs"]> {
|
||||
return getLightExport("getWebAuthAgeMs")(...args);
|
||||
}
|
||||
|
||||
export function logWebSelfId(
|
||||
...args: Parameters<WhatsAppLightModule["logWebSelfId"]>
|
||||
): ReturnType<WhatsAppLightModule["logWebSelfId"]> {
|
||||
return getLightExport("logWebSelfId")(...args);
|
||||
}
|
||||
|
||||
export function loginWeb(
|
||||
...args: Parameters<WhatsAppHeavyModule["loginWeb"]>
|
||||
): ReturnType<WhatsAppHeavyModule["loginWeb"]> {
|
||||
return loadWhatsAppHeavyModule().then((loaded) => loaded.loginWeb(...args));
|
||||
}
|
||||
|
||||
export function logoutWeb(
|
||||
...args: Parameters<WhatsAppLightModule["logoutWeb"]>
|
||||
): ReturnType<WhatsAppLightModule["logoutWeb"]> {
|
||||
return getLightExport("logoutWeb")(...args);
|
||||
}
|
||||
|
||||
export function readWebSelfId(
|
||||
...args: Parameters<WhatsAppLightModule["readWebSelfId"]>
|
||||
): ReturnType<WhatsAppLightModule["readWebSelfId"]> {
|
||||
return getLightExport("readWebSelfId")(...args);
|
||||
}
|
||||
|
||||
export function webAuthExists(
|
||||
...args: Parameters<WhatsAppLightModule["webAuthExists"]>
|
||||
): ReturnType<WhatsAppLightModule["webAuthExists"]> {
|
||||
return getLightExport("webAuthExists")(...args);
|
||||
}
|
||||
|
||||
export function sendMessageWhatsApp(
|
||||
...args: Parameters<WhatsAppHeavyModule["sendMessageWhatsApp"]>
|
||||
): ReturnType<WhatsAppHeavyModule["sendMessageWhatsApp"]> {
|
||||
return loadWhatsAppHeavyModule().then((loaded) => loaded.sendMessageWhatsApp(...args));
|
||||
}
|
||||
|
||||
export function sendPollWhatsApp(
|
||||
...args: Parameters<WhatsAppHeavyModule["sendPollWhatsApp"]>
|
||||
): ReturnType<WhatsAppHeavyModule["sendPollWhatsApp"]> {
|
||||
return loadWhatsAppHeavyModule().then((loaded) => loaded.sendPollWhatsApp(...args));
|
||||
}
|
||||
|
||||
export function sendReactionWhatsApp(
|
||||
...args: Parameters<WhatsAppHeavyModule["sendReactionWhatsApp"]>
|
||||
): ReturnType<WhatsAppHeavyModule["sendReactionWhatsApp"]> {
|
||||
return loadWhatsAppHeavyModule().then((loaded) => loaded.sendReactionWhatsApp(...args));
|
||||
}
|
||||
|
||||
export function createRuntimeWhatsAppLoginTool(
|
||||
...args: Parameters<WhatsAppLightModule["createWhatsAppLoginTool"]>
|
||||
): ReturnType<WhatsAppLightModule["createWhatsAppLoginTool"]> {
|
||||
return getLightExport("createWhatsAppLoginTool")(...args);
|
||||
}
|
||||
|
||||
export function createWaSocket(
|
||||
...args: Parameters<WhatsAppHeavyModule["createWaSocket"]>
|
||||
): ReturnType<WhatsAppHeavyModule["createWaSocket"]> {
|
||||
return loadWhatsAppHeavyModule().then((loaded) => loaded.createWaSocket(...args));
|
||||
}
|
||||
|
||||
export function formatError(
|
||||
...args: Parameters<WhatsAppLightModule["formatError"]>
|
||||
): ReturnType<WhatsAppLightModule["formatError"]> {
|
||||
return getLightExport("formatError")(...args);
|
||||
}
|
||||
|
||||
export function getStatusCode(
|
||||
...args: Parameters<WhatsAppLightModule["getStatusCode"]>
|
||||
): ReturnType<WhatsAppLightModule["getStatusCode"]> {
|
||||
return getLightExport("getStatusCode")(...args);
|
||||
}
|
||||
|
||||
export function pickWebChannel(
|
||||
...args: Parameters<WhatsAppLightModule["pickWebChannel"]>
|
||||
): ReturnType<WhatsAppLightModule["pickWebChannel"]> {
|
||||
return getLightExport("pickWebChannel")(...args);
|
||||
}
|
||||
|
||||
export function resolveWaWebAuthDir(): WhatsAppLightModule["WA_WEB_AUTH_DIR"] {
|
||||
return getLightExport("WA_WEB_AUTH_DIR");
|
||||
}
|
||||
|
||||
export async function handleWhatsAppAction(
|
||||
...args: Parameters<WhatsAppHeavyModule["handleWhatsAppAction"]>
|
||||
): ReturnType<WhatsAppHeavyModule["handleWhatsAppAction"]> {
|
||||
return (await getHeavyExport("handleWhatsAppAction"))(...args);
|
||||
}
|
||||
|
||||
export async function loadWebMedia(
|
||||
...args: Parameters<typeof loadWebMediaImpl>
|
||||
): ReturnType<typeof loadWebMediaImpl> {
|
||||
return await loadWebMediaImpl(...args);
|
||||
}
|
||||
|
||||
export async function loadWebMediaRaw(
|
||||
...args: Parameters<typeof loadWebMediaRawImpl>
|
||||
): ReturnType<typeof loadWebMediaRawImpl> {
|
||||
return await loadWebMediaRawImpl(...args);
|
||||
}
|
||||
|
||||
export function monitorWebChannel(
|
||||
...args: Parameters<WhatsAppHeavyModule["monitorWebChannel"]>
|
||||
): ReturnType<WhatsAppHeavyModule["monitorWebChannel"]> {
|
||||
return loadWhatsAppHeavyModule().then((loaded) => loaded.monitorWebChannel(...args));
|
||||
}
|
||||
|
||||
export async function monitorWebInbox(
|
||||
...args: Parameters<WhatsAppHeavyModule["monitorWebInbox"]>
|
||||
): ReturnType<WhatsAppHeavyModule["monitorWebInbox"]> {
|
||||
return (await getHeavyExport("monitorWebInbox"))(...args);
|
||||
}
|
||||
|
||||
export async function optimizeImageToJpeg(
|
||||
...args: Parameters<typeof optimizeImageToJpegImpl>
|
||||
): ReturnType<typeof optimizeImageToJpegImpl> {
|
||||
return await optimizeImageToJpegImpl(...args);
|
||||
}
|
||||
|
||||
export async function runWebHeartbeatOnce(
|
||||
...args: Parameters<WhatsAppHeavyModule["runWebHeartbeatOnce"]>
|
||||
): ReturnType<WhatsAppHeavyModule["runWebHeartbeatOnce"]> {
|
||||
return (await getHeavyExport("runWebHeartbeatOnce"))(...args);
|
||||
}
|
||||
|
||||
export async function startWebLoginWithQr(
|
||||
...args: Parameters<WhatsAppHeavyModule["startWebLoginWithQr"]>
|
||||
): ReturnType<WhatsAppHeavyModule["startWebLoginWithQr"]> {
|
||||
return (await getHeavyExport("startWebLoginWithQr"))(...args);
|
||||
}
|
||||
|
||||
export async function waitForWaConnection(
|
||||
...args: Parameters<WhatsAppHeavyModule["waitForWaConnection"]>
|
||||
): ReturnType<WhatsAppHeavyModule["waitForWaConnection"]> {
|
||||
return (await getHeavyExport("waitForWaConnection"))(...args);
|
||||
}
|
||||
|
||||
export async function waitForWebLogin(
|
||||
...args: Parameters<WhatsAppHeavyModule["waitForWebLogin"]>
|
||||
): ReturnType<WhatsAppHeavyModule["waitForWebLogin"]> {
|
||||
return (await getHeavyExport("waitForWebLogin"))(...args);
|
||||
}
|
||||
|
||||
export const extractMediaPlaceholder = (
|
||||
...args: Parameters<WhatsAppHeavyModule["extractMediaPlaceholder"]>
|
||||
) => loadCurrentHeavyModuleSync().extractMediaPlaceholder(...args);
|
||||
|
||||
export const extractText = (...args: Parameters<WhatsAppHeavyModule["extractText"]>) =>
|
||||
loadCurrentHeavyModuleSync().extractText(...args);
|
||||
|
||||
export function getDefaultLocalRoots(
|
||||
...args: Parameters<typeof getDefaultLocalRootsImpl>
|
||||
): ReturnType<typeof getDefaultLocalRootsImpl> {
|
||||
return getDefaultLocalRootsImpl(...args);
|
||||
}
|
||||
|
||||
export function resolveHeartbeatRecipients(
|
||||
...args: Parameters<typeof resolveWhatsAppHeartbeatRecipients>
|
||||
): ReturnType<typeof resolveWhatsAppHeartbeatRecipients> {
|
||||
return resolveWhatsAppHeartbeatRecipients(...args);
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
export { createWhatsAppLoginTool as createRuntimeWhatsAppLoginTool } from "openclaw/plugin-sdk/whatsapp";
|
||||
export { createRuntimeWhatsAppLoginTool } from "./runtime-whatsapp-boundary.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { loginWeb as loginWebImpl } from "openclaw/plugin-sdk/whatsapp";
|
||||
import { loginWeb as loginWebImpl } from "./runtime-whatsapp-boundary.js";
|
||||
import type { PluginRuntime } from "./types.js";
|
||||
|
||||
type RuntimeWhatsAppLogin = Pick<PluginRuntime["channel"]["whatsapp"], "loginWeb">;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
sendMessageWhatsApp as sendMessageWhatsAppImpl,
|
||||
sendPollWhatsApp as sendPollWhatsAppImpl,
|
||||
} from "openclaw/plugin-sdk/whatsapp";
|
||||
} from "./runtime-whatsapp-boundary.js";
|
||||
import type { PluginRuntime } from "./types.js";
|
||||
|
||||
type RuntimeWhatsAppOutbound = Pick<
|
||||
|
||||
@@ -1,90 +1,21 @@
|
||||
import { getActiveWebListener } from "openclaw/plugin-sdk/whatsapp";
|
||||
import {
|
||||
createRuntimeWhatsAppLoginTool,
|
||||
getActiveWebListener,
|
||||
getWebAuthAgeMs,
|
||||
handleWhatsAppAction,
|
||||
logWebSelfId,
|
||||
loginWeb,
|
||||
logoutWeb,
|
||||
monitorWebChannel,
|
||||
readWebSelfId,
|
||||
sendMessageWhatsApp,
|
||||
sendPollWhatsApp,
|
||||
startWebLoginWithQr,
|
||||
waitForWebLogin,
|
||||
webAuthExists,
|
||||
} from "openclaw/plugin-sdk/whatsapp";
|
||||
import {
|
||||
createLazyRuntimeMethodBinder,
|
||||
createLazyRuntimeSurface,
|
||||
} from "../../shared/lazy-runtime.js";
|
||||
import { createRuntimeWhatsAppLoginTool } from "./runtime-whatsapp-login-tool.js";
|
||||
} from "./runtime-whatsapp-boundary.js";
|
||||
import type { PluginRuntime } from "./types.js";
|
||||
|
||||
const loadWebOutbound = createLazyRuntimeSurface(
|
||||
() => import("./runtime-whatsapp-outbound.runtime.js"),
|
||||
({ runtimeWhatsAppOutbound }) => runtimeWhatsAppOutbound,
|
||||
);
|
||||
|
||||
const loadWebLogin = createLazyRuntimeSurface(
|
||||
() => import("./runtime-whatsapp-login.runtime.js"),
|
||||
({ runtimeWhatsAppLogin }) => runtimeWhatsAppLogin,
|
||||
);
|
||||
|
||||
const bindWhatsAppOutboundMethod = createLazyRuntimeMethodBinder(loadWebOutbound);
|
||||
const bindWhatsAppLoginMethod = createLazyRuntimeMethodBinder(loadWebLogin);
|
||||
|
||||
const sendMessageWhatsAppLazy = bindWhatsAppOutboundMethod(
|
||||
(runtimeWhatsAppOutbound) => runtimeWhatsAppOutbound.sendMessageWhatsApp,
|
||||
);
|
||||
const sendPollWhatsAppLazy = bindWhatsAppOutboundMethod(
|
||||
(runtimeWhatsAppOutbound) => runtimeWhatsAppOutbound.sendPollWhatsApp,
|
||||
);
|
||||
const loginWebLazy = bindWhatsAppLoginMethod(
|
||||
(runtimeWhatsAppLogin) => runtimeWhatsAppLogin.loginWeb,
|
||||
);
|
||||
|
||||
const startWebLoginWithQrLazy: PluginRuntime["channel"]["whatsapp"]["startWebLoginWithQr"] = async (
|
||||
...args
|
||||
) => {
|
||||
const { startWebLoginWithQr } = await loadWebLoginQr();
|
||||
return startWebLoginWithQr(...args);
|
||||
};
|
||||
|
||||
const waitForWebLoginLazy: PluginRuntime["channel"]["whatsapp"]["waitForWebLogin"] = async (
|
||||
...args
|
||||
) => {
|
||||
const { waitForWebLogin } = await loadWebLoginQr();
|
||||
return waitForWebLogin(...args);
|
||||
};
|
||||
|
||||
const monitorWebChannelLazy: PluginRuntime["channel"]["whatsapp"]["monitorWebChannel"] = async (
|
||||
...args
|
||||
) => {
|
||||
const { monitorWebChannel } = await loadWebChannel();
|
||||
return monitorWebChannel(...args);
|
||||
};
|
||||
|
||||
const handleWhatsAppActionLazy: PluginRuntime["channel"]["whatsapp"]["handleWhatsAppAction"] =
|
||||
async (...args) => {
|
||||
const { handleWhatsAppAction } = await loadWhatsAppActions();
|
||||
return handleWhatsAppAction(...args);
|
||||
};
|
||||
|
||||
let webLoginQrPromise: Promise<typeof import("openclaw/plugin-sdk/whatsapp-login-qr")> | null =
|
||||
null;
|
||||
let webChannelPromise: Promise<typeof import("../../channels/web/index.js")> | null = null;
|
||||
let whatsappActionsPromise: Promise<
|
||||
typeof import("openclaw/plugin-sdk/whatsapp-action-runtime")
|
||||
> | null = null;
|
||||
|
||||
function loadWebLoginQr() {
|
||||
webLoginQrPromise ??= import("openclaw/plugin-sdk/whatsapp-login-qr");
|
||||
return webLoginQrPromise;
|
||||
}
|
||||
|
||||
function loadWebChannel() {
|
||||
webChannelPromise ??= import("../../channels/web/index.js");
|
||||
return webChannelPromise;
|
||||
}
|
||||
|
||||
function loadWhatsAppActions() {
|
||||
whatsappActionsPromise ??= import("openclaw/plugin-sdk/whatsapp-action-runtime");
|
||||
return whatsappActionsPromise;
|
||||
}
|
||||
|
||||
export function createRuntimeWhatsApp(): PluginRuntime["channel"]["whatsapp"] {
|
||||
return {
|
||||
getActiveWebListener,
|
||||
@@ -93,13 +24,13 @@ export function createRuntimeWhatsApp(): PluginRuntime["channel"]["whatsapp"] {
|
||||
logWebSelfId,
|
||||
readWebSelfId,
|
||||
webAuthExists,
|
||||
sendMessageWhatsApp: sendMessageWhatsAppLazy,
|
||||
sendPollWhatsApp: sendPollWhatsAppLazy,
|
||||
loginWeb: loginWebLazy,
|
||||
startWebLoginWithQr: startWebLoginWithQrLazy,
|
||||
waitForWebLogin: waitForWebLoginLazy,
|
||||
monitorWebChannel: monitorWebChannelLazy,
|
||||
handleWhatsAppAction: handleWhatsAppActionLazy,
|
||||
sendMessageWhatsApp,
|
||||
sendPollWhatsApp,
|
||||
loginWeb,
|
||||
startWebLoginWithQr,
|
||||
waitForWebLogin,
|
||||
monitorWebChannel,
|
||||
handleWhatsAppAction,
|
||||
createLoginTool: createRuntimeWhatsAppLoginTool,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -205,19 +205,19 @@ export type PluginRuntimeChannel = {
|
||||
sendMessageIMessage: typeof import("../../../extensions/imessage/runtime-api.js").sendMessageIMessage;
|
||||
};
|
||||
whatsapp: {
|
||||
getActiveWebListener: typeof import("openclaw/plugin-sdk/whatsapp").getActiveWebListener;
|
||||
getWebAuthAgeMs: typeof import("openclaw/plugin-sdk/whatsapp").getWebAuthAgeMs;
|
||||
logoutWeb: typeof import("openclaw/plugin-sdk/whatsapp").logoutWeb;
|
||||
logWebSelfId: typeof import("openclaw/plugin-sdk/whatsapp").logWebSelfId;
|
||||
readWebSelfId: typeof import("openclaw/plugin-sdk/whatsapp").readWebSelfId;
|
||||
webAuthExists: typeof import("openclaw/plugin-sdk/whatsapp").webAuthExists;
|
||||
sendMessageWhatsApp: typeof import("openclaw/plugin-sdk/whatsapp").sendMessageWhatsApp;
|
||||
sendPollWhatsApp: typeof import("openclaw/plugin-sdk/whatsapp").sendPollWhatsApp;
|
||||
loginWeb: typeof import("openclaw/plugin-sdk/whatsapp").loginWeb;
|
||||
startWebLoginWithQr: typeof import("openclaw/plugin-sdk/whatsapp-login-qr").startWebLoginWithQr;
|
||||
waitForWebLogin: typeof import("openclaw/plugin-sdk/whatsapp-login-qr").waitForWebLogin;
|
||||
monitorWebChannel: typeof import("../../channels/web/index.js").monitorWebChannel;
|
||||
handleWhatsAppAction: typeof import("openclaw/plugin-sdk/whatsapp-action-runtime").handleWhatsAppAction;
|
||||
getActiveWebListener: typeof import("./runtime-whatsapp-boundary.js").getActiveWebListener;
|
||||
getWebAuthAgeMs: typeof import("./runtime-whatsapp-boundary.js").getWebAuthAgeMs;
|
||||
logoutWeb: typeof import("./runtime-whatsapp-boundary.js").logoutWeb;
|
||||
logWebSelfId: typeof import("./runtime-whatsapp-boundary.js").logWebSelfId;
|
||||
readWebSelfId: typeof import("./runtime-whatsapp-boundary.js").readWebSelfId;
|
||||
webAuthExists: typeof import("./runtime-whatsapp-boundary.js").webAuthExists;
|
||||
sendMessageWhatsApp: typeof import("./runtime-whatsapp-boundary.js").sendMessageWhatsApp;
|
||||
sendPollWhatsApp: typeof import("./runtime-whatsapp-boundary.js").sendPollWhatsApp;
|
||||
loginWeb: typeof import("./runtime-whatsapp-boundary.js").loginWeb;
|
||||
startWebLoginWithQr: typeof import("./runtime-whatsapp-boundary.js").startWebLoginWithQr;
|
||||
waitForWebLogin: typeof import("./runtime-whatsapp-boundary.js").waitForWebLogin;
|
||||
monitorWebChannel: typeof import("./runtime-whatsapp-boundary.js").monitorWebChannel;
|
||||
handleWhatsAppAction: typeof import("./runtime-whatsapp-boundary.js").handleWhatsAppAction;
|
||||
createLoginTool: typeof import("./runtime-whatsapp-login-tool.js").createRuntimeWhatsAppLoginTool;
|
||||
};
|
||||
line: {
|
||||
|
||||
@@ -39,7 +39,7 @@ export type PluginRuntimeCore = {
|
||||
formatNativeDependencyHint: typeof import("./native-deps.js").formatNativeDependencyHint;
|
||||
};
|
||||
media: {
|
||||
loadWebMedia: typeof import("../../../extensions/whatsapp/runtime-api.js").loadWebMedia;
|
||||
loadWebMedia: typeof import("../../media/web-media.js").loadWebMedia;
|
||||
detectMime: typeof import("../../media/mime.js").detectMime;
|
||||
mediaKindFromMime: typeof import("../../media/constants.js").mediaKindFromMime;
|
||||
isVoiceCompatibleAudio: typeof import("../../media/audio.js").isVoiceCompatibleAudio;
|
||||
|
||||
185
src/plugins/sdk-alias.ts
Normal file
185
src/plugins/sdk-alias.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
|
||||
|
||||
type PluginSdkAliasCandidateKind = "dist" | "src";
|
||||
|
||||
export type LoaderModuleResolveParams = {
|
||||
modulePath?: string;
|
||||
argv1?: string;
|
||||
cwd?: string;
|
||||
moduleUrl?: string;
|
||||
};
|
||||
|
||||
function resolveLoaderModulePath(params: LoaderModuleResolveParams = {}): string {
|
||||
return params.modulePath ?? fileURLToPath(params.moduleUrl ?? import.meta.url);
|
||||
}
|
||||
|
||||
export function resolveLoaderPackageRoot(
|
||||
params: LoaderModuleResolveParams & { modulePath: string },
|
||||
): string | null {
|
||||
const cwd = params.cwd ?? path.dirname(params.modulePath);
|
||||
const fromModulePath = resolveOpenClawPackageRootSync({ cwd });
|
||||
if (fromModulePath) {
|
||||
return fromModulePath;
|
||||
}
|
||||
const argv1 = params.argv1 ?? process.argv[1];
|
||||
const moduleUrl = params.moduleUrl ?? (params.modulePath ? undefined : import.meta.url);
|
||||
return resolveOpenClawPackageRootSync({
|
||||
cwd,
|
||||
...(argv1 ? { argv1 } : {}),
|
||||
...(moduleUrl ? { moduleUrl } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
export function resolvePluginSdkAliasCandidateOrder(params: {
|
||||
modulePath: string;
|
||||
isProduction: boolean;
|
||||
}): PluginSdkAliasCandidateKind[] {
|
||||
const normalizedModulePath = params.modulePath.replace(/\\/g, "/");
|
||||
const isDistRuntime = normalizedModulePath.includes("/dist/");
|
||||
return isDistRuntime || params.isProduction ? ["dist", "src"] : ["src", "dist"];
|
||||
}
|
||||
|
||||
export function listPluginSdkAliasCandidates(params: {
|
||||
srcFile: string;
|
||||
distFile: string;
|
||||
modulePath: string;
|
||||
argv1?: string;
|
||||
cwd?: string;
|
||||
moduleUrl?: string;
|
||||
}) {
|
||||
const orderedKinds = resolvePluginSdkAliasCandidateOrder({
|
||||
modulePath: params.modulePath,
|
||||
isProduction: process.env.NODE_ENV === "production",
|
||||
});
|
||||
const packageRoot = resolveLoaderPackageRoot(params);
|
||||
if (packageRoot) {
|
||||
const candidateMap = {
|
||||
src: path.join(packageRoot, "src", "plugin-sdk", params.srcFile),
|
||||
dist: path.join(packageRoot, "dist", "plugin-sdk", params.distFile),
|
||||
} as const;
|
||||
return orderedKinds.map((kind) => candidateMap[kind]);
|
||||
}
|
||||
let cursor = path.dirname(params.modulePath);
|
||||
const candidates: string[] = [];
|
||||
for (let i = 0; i < 6; i += 1) {
|
||||
const candidateMap = {
|
||||
src: path.join(cursor, "src", "plugin-sdk", params.srcFile),
|
||||
dist: path.join(cursor, "dist", "plugin-sdk", params.distFile),
|
||||
} as const;
|
||||
for (const kind of orderedKinds) {
|
||||
candidates.push(candidateMap[kind]);
|
||||
}
|
||||
const parent = path.dirname(cursor);
|
||||
if (parent === cursor) {
|
||||
break;
|
||||
}
|
||||
cursor = parent;
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
export function resolvePluginSdkAliasFile(params: {
|
||||
srcFile: string;
|
||||
distFile: string;
|
||||
modulePath?: string;
|
||||
argv1?: string;
|
||||
cwd?: string;
|
||||
moduleUrl?: string;
|
||||
}): string | null {
|
||||
try {
|
||||
const modulePath = resolveLoaderModulePath(params);
|
||||
for (const candidate of listPluginSdkAliasCandidates({
|
||||
srcFile: params.srcFile,
|
||||
distFile: params.distFile,
|
||||
modulePath,
|
||||
argv1: params.argv1,
|
||||
cwd: params.cwd,
|
||||
moduleUrl: params.moduleUrl,
|
||||
})) {
|
||||
if (fs.existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const cachedPluginSdkExportedSubpaths = new Map<string, string[]>();
|
||||
|
||||
export function listPluginSdkExportedSubpaths(params: { modulePath?: string } = {}): string[] {
|
||||
const modulePath = params.modulePath ?? fileURLToPath(import.meta.url);
|
||||
const packageRoot = resolveOpenClawPackageRootSync({
|
||||
cwd: path.dirname(modulePath),
|
||||
});
|
||||
if (!packageRoot) {
|
||||
return [];
|
||||
}
|
||||
const cached = cachedPluginSdkExportedSubpaths.get(packageRoot);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
try {
|
||||
const pkgRaw = fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8");
|
||||
const pkg = JSON.parse(pkgRaw) as {
|
||||
exports?: Record<string, unknown>;
|
||||
};
|
||||
const subpaths = Object.keys(pkg.exports ?? {})
|
||||
.filter((key) => key.startsWith("./plugin-sdk/"))
|
||||
.map((key) => key.slice("./plugin-sdk/".length))
|
||||
.filter((subpath) => Boolean(subpath) && !subpath.includes("/"))
|
||||
.toSorted();
|
||||
cachedPluginSdkExportedSubpaths.set(packageRoot, subpaths);
|
||||
return subpaths;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function resolvePluginSdkScopedAliasMap(
|
||||
params: { modulePath?: string } = {},
|
||||
): Record<string, string> {
|
||||
const aliasMap: Record<string, string> = {};
|
||||
for (const subpath of listPluginSdkExportedSubpaths(params)) {
|
||||
const resolved = resolvePluginSdkAliasFile({
|
||||
srcFile: `${subpath}.ts`,
|
||||
distFile: `${subpath}.js`,
|
||||
modulePath: params.modulePath,
|
||||
});
|
||||
if (resolved) {
|
||||
aliasMap[`openclaw/plugin-sdk/${subpath}`] = resolved;
|
||||
}
|
||||
}
|
||||
return aliasMap;
|
||||
}
|
||||
|
||||
export function buildPluginLoaderJitiOptions(aliasMap: Record<string, string>) {
|
||||
return {
|
||||
interopDefault: true,
|
||||
// Prefer Node's native sync ESM loader for built dist/*.js modules so
|
||||
// bundled plugins and plugin-sdk subpaths stay on the canonical module graph.
|
||||
tryNative: true,
|
||||
extensions: [".ts", ".tsx", ".mts", ".cts", ".mtsx", ".ctsx", ".js", ".mjs", ".cjs", ".json"],
|
||||
...(Object.keys(aliasMap).length > 0
|
||||
? {
|
||||
alias: aliasMap,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
export function shouldPreferNativeJiti(modulePath: string): boolean {
|
||||
switch (path.extname(modulePath).toLowerCase()) {
|
||||
case ".js":
|
||||
case ".mjs":
|
||||
case ".cjs":
|
||||
case ".json":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user