diff --git a/scripts/stage-bundled-plugin-runtime.mjs b/scripts/stage-bundled-plugin-runtime.mjs index 4b6b50412e8..077d8f77f44 100644 --- a/scripts/stage-bundled-plugin-runtime.mjs +++ b/scripts/stage-bundled-plugin-runtime.mjs @@ -88,24 +88,10 @@ function stagePluginRuntimeOverlay(sourceDir, targetDir) { function linkPluginNodeModules(params) { const runtimeNodeModulesDir = path.join(params.runtimePluginDir, "node_modules"); removePathIfExists(runtimeNodeModulesDir); - if (params.distPluginDir) { - removePathIfExists(path.join(params.distPluginDir, "node_modules")); - } if (!fs.existsSync(params.sourcePluginNodeModulesDir)) { return; } fs.symlinkSync(params.sourcePluginNodeModulesDir, runtimeNodeModulesDir, symlinkType()); - - // Runtime wrappers re-export from dist/extensions//index.js, so Node - // resolves bare-specifier dependencies relative to the dist plugin directory. - // copy-bundled-plugin-metadata removes dist node_modules; restore the link here. - if (params.distPluginDir) { - removePathIfExists(path.join(params.distPluginDir, "node_modules")); - } - if (params.distPluginDir) { - const distNodeModulesDir = path.join(params.distPluginDir, "node_modules"); - fs.symlinkSync(params.sourcePluginNodeModulesDir, distNodeModulesDir, symlinkType()); - } } export function stageBundledPluginRuntime(params = {}) { diff --git a/scripts/write-plugin-sdk-entry-dts.ts b/scripts/write-plugin-sdk-entry-dts.ts index 832368bbcd3..b4fa602eba9 100644 --- a/scripts/write-plugin-sdk-entry-dts.ts +++ b/scripts/write-plugin-sdk-entry-dts.ts @@ -2,14 +2,79 @@ import fs from "node:fs"; import path from "node:path"; import { pluginSdkEntrypoints } from "./lib/plugin-sdk-entries.mjs"; +const RUNTIME_SHIMS: Partial> = { + "secret-input-runtime": [ + "export {", + " hasConfiguredSecretInput,", + " normalizeResolvedSecretInputString,", + " normalizeSecretInputString,", + '} from "./config-runtime.js";', + "", + ].join("\n"), + "webhook-path": [ + "/** Normalize webhook paths into the canonical registry form used by route lookup. */", + "export function normalizeWebhookPath(raw) {", + " const trimmed = raw.trim();", + " if (!trimmed) {", + ' return "/";', + " }", + ' const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;', + ' if (withSlash.length > 1 && withSlash.endsWith("/")) {', + " return withSlash.slice(0, -1);", + " }", + " return withSlash;", + "}", + "", + "/** Resolve the effective webhook path from explicit path, URL, or default fallback. */", + "export function resolveWebhookPath(params) {", + " const trimmedPath = params.webhookPath?.trim();", + " if (trimmedPath) {", + " return normalizeWebhookPath(trimmedPath);", + " }", + " if (params.webhookUrl?.trim()) {", + " try {", + " const parsed = new URL(params.webhookUrl);", + ' return normalizeWebhookPath(parsed.pathname || "/");', + " } catch {", + " return null;", + " }", + " }", + " return params.defaultPath ?? null;", + "}", + "", + ].join("\n"), +}; + +const TYPE_SHIMS: Partial> = { + "secret-input-runtime": [ + "export {", + " hasConfiguredSecretInput,", + " normalizeResolvedSecretInputString,", + " normalizeSecretInputString,", + '} from "./config-runtime.js";', + "", + ].join("\n"), +}; + // `tsc` emits declarations under `dist/plugin-sdk/src/plugin-sdk/*` because the source lives // at `src/plugin-sdk/*` and `rootDir` is `.` (repo root, to support cross-src/extensions refs). // // Our package export map points subpath `types` at `dist/plugin-sdk/.d.ts`, so we // generate stable entry d.ts files that re-export the real declarations. for (const entry of pluginSdkEntrypoints) { - const out = path.join(process.cwd(), `dist/plugin-sdk/${entry}.d.ts`); - fs.mkdirSync(path.dirname(out), { recursive: true }); - // NodeNext: reference the runtime specifier with `.js`, TS will map it to `.d.ts`. - fs.writeFileSync(out, `export * from "./src/plugin-sdk/${entry}.js";\n`, "utf8"); + const typeOut = path.join(process.cwd(), `dist/plugin-sdk/${entry}.d.ts`); + fs.mkdirSync(path.dirname(typeOut), { recursive: true }); + fs.writeFileSync( + typeOut, + TYPE_SHIMS[entry] ?? `export * from "./src/plugin-sdk/${entry}.js";\n`, + "utf8", + ); + + const runtimeShim = RUNTIME_SHIMS[entry]; + if (!runtimeShim) { + continue; + } + const runtimeOut = path.join(process.cwd(), `dist/plugin-sdk/${entry}.js`); + fs.mkdirSync(path.dirname(runtimeOut), { recursive: true }); + fs.writeFileSync(runtimeOut, runtimeShim, "utf8"); } diff --git a/src/plugins/stage-bundled-plugin-runtime.test.ts b/src/plugins/stage-bundled-plugin-runtime.test.ts index fef9a725799..3ef875a88a6 100644 --- a/src/plugins/stage-bundled-plugin-runtime.test.ts +++ b/src/plugins/stage-bundled-plugin-runtime.test.ts @@ -49,12 +49,7 @@ describe("stageBundledPluginRuntime", () => { expect(fs.realpathSync(path.join(runtimePluginDir, "node_modules"))).toBe( fs.realpathSync(sourcePluginNodeModulesDir), ); - - // dist/ also gets a node_modules symlink so bare-specifier resolution works - // from the actual code location that the runtime wrapper re-exports into - const distNodeModules = path.join(distPluginDir, "node_modules"); - expect(fs.lstatSync(distNodeModules).isSymbolicLink()).toBe(true); - expect(fs.realpathSync(distNodeModules)).toBe(fs.realpathSync(sourcePluginNodeModulesDir)); + expect(fs.existsSync(path.join(distPluginDir, "node_modules"))).toBe(false); }); it("writes wrappers that forward plugin entry imports into canonical dist files", async () => {