@zapier/zapier-sdk-cli 0.43.4 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.43.4",
3
+ "version": "0.44.0",
4
4
  "description": "Command line interface for Zapier SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
package/dist/src/cli.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { Command, CommanderError } from "commander";
3
3
  import { generateCliCommands } from "./utils/cli-generator";
4
4
  import { createZapierCliSdk } from "./sdk";
5
+ import { resolveExtensions } from "./utils/extensions";
5
6
  import packageJson from "../package.json" with { type: "json" };
6
7
  import { ZapierCliError } from "./utils/errors";
7
8
  import { checkAndNotifyUpdates } from "./utils/version-checker";
@@ -102,24 +103,27 @@ for (const { camelName, kebabFlag } of booleanFlags) {
102
103
  flagOverrides[camelName] = true;
103
104
  }
104
105
  }
105
- // Create CLI SDK instance with all plugins and URL options
106
- const sdk = createZapierCliSdk({
107
- debug: isDebugMode,
108
- credentials,
109
- baseUrl,
110
- trackingBaseUrl,
111
- maxNetworkRetries,
112
- maxNetworkRetryDelayMs,
113
- ...flagOverrides,
114
- });
115
- // Auth commands now handled by plugins
116
- // Generate CLI commands from SDK schemas (including CLI plugins)
117
- generateCliCommands(program, sdk);
118
- // MCP command now handled by plugin
119
106
  // Override Commander's default exit behavior to handle our custom errors
120
107
  program.exitOverride();
121
108
  (async () => {
122
109
  let exitCode = 0;
110
+ // Resolve extension packages declared via the ZAPIER_SDK_EXTENSIONS env
111
+ // var. Pre-resolving here keeps createZapierCliSdk synchronous for
112
+ // programmatic callers.
113
+ const extensions = await resolveExtensions();
114
+ // Create CLI SDK instance with all plugins and URL options
115
+ const sdk = createZapierCliSdk({
116
+ debug: isDebugMode,
117
+ credentials,
118
+ baseUrl,
119
+ trackingBaseUrl,
120
+ maxNetworkRetries,
121
+ maxNetworkRetryDelayMs,
122
+ ...flagOverrides,
123
+ extensions,
124
+ });
125
+ // Generate CLI commands from SDK schemas (including CLI plugins and extensions)
126
+ generateCliCommands(program, sdk);
123
127
  // Start version checking non-blocking
124
128
  const versionCheckPromise = checkAndNotifyUpdates({
125
129
  packageName: packageJson.name,
@@ -1,8 +1,10 @@
1
+ import { type Plugin, type PluginProvides } from "@zapier/zapier-sdk";
1
2
  export declare const mcpPlugin: (sdk: {
2
3
  context: {
3
4
  options?: {
4
5
  debug?: boolean;
5
6
  };
7
+ extensions?: Plugin<unknown, PluginProvides>[];
6
8
  };
7
9
  } & {
8
10
  context: import("@zapier/zapier-sdk").EventEmissionContext;
@@ -6,7 +6,14 @@ export const mcpPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
6
6
  categories: ["utility"],
7
7
  inputSchema: McpSchema,
8
8
  handler: async ({ sdk, options }) => {
9
- // Pass through the SDK's debug option to the MCP server
10
- await startMcpServer({ ...options, debug: sdk.context.options?.debug });
9
+ // Forward debug + the extensions resolved at CLI startup so the MCP
10
+ // server's registry includes extension functions as tools. Without
11
+ // this forward, MCP would build a vanilla SDK and the CLI/MCP
12
+ // surfaces would diverge.
13
+ await startMcpServer({
14
+ ...options,
15
+ debug: sdk.context.options?.debug,
16
+ extensions: sdk.context.extensions,
17
+ });
11
18
  },
12
19
  }));
package/dist/src/sdk.d.ts CHANGED
@@ -1,6 +1,14 @@
1
- import { type ZapierSdkOptions } from "@zapier/zapier-sdk";
1
+ import { type Plugin, type PluginProvides, type ZapierSdkOptions } from "@zapier/zapier-sdk";
2
2
  import type { ZapierSdkCli } from "./types/sdk";
3
3
  export interface ZapierCliSdkOptions extends ZapierSdkOptions {
4
+ /**
5
+ * Extra plugins discovered from `@zapier/zapier-sdk` extension packages.
6
+ * Pre-resolved by `cli.ts` (`utils/extensions.ts`) so this factory stays
7
+ * synchronous. Each plugin is layered onto the chain after all built-in
8
+ * CLI plugins, so its functions appear in `getRegistry({ package: "cli" })`
9
+ * automatically.
10
+ */
11
+ extensions?: Plugin<unknown, PluginProvides>[];
4
12
  }
5
13
  /**
6
14
  * Create a Zapier SDK instance configured specifically for the CLI
package/dist/src/sdk.js CHANGED
@@ -8,11 +8,19 @@ injectCliLogin(cliLogin);
8
8
  * Includes all CLI-specific plugins in addition to the standard SDK functionality
9
9
  */
10
10
  export function createZapierCliSdk(options = {}) {
11
- return createZapierSdk({
12
- ...options,
13
- eventEmission: { ...options.eventEmission, callContext: "cli" },
11
+ const { extensions = [], ...sdkOptions } = options;
12
+ // Stash the resolved extensions on context so `mcpPlugin` can forward
13
+ // them to `startMcpServer`. Without this, MCP would build a vanilla SDK
14
+ // with no extensions and the CLI/MCP surfaces would diverge.
15
+ const extensionsContextPlugin = () => ({
16
+ context: { extensions },
17
+ });
18
+ let chain = createZapierSdk({
19
+ ...sdkOptions,
20
+ eventEmission: { ...sdkOptions.eventEmission, callContext: "cli" },
14
21
  callerPackage: { name: packageJson.name, version: packageJson.version },
15
22
  })
23
+ .addPlugin(extensionsContextPlugin)
16
24
  .addPlugin(generateAppTypesPlugin)
17
25
  .addPlugin(buildManifestPlugin)
18
26
  .addPlugin(bundleCodePlugin)
@@ -25,4 +33,19 @@ export function createZapierCliSdk(options = {}) {
25
33
  .addPlugin(loginPlugin)
26
34
  .addPlugin(logoutPlugin)
27
35
  .addPlugin(cliOverridesPlugin);
36
+ // Construct extensions defensively. The loader (`utils/extensions.ts`)
37
+ // already isolates *load*-time failures (failed dynamic imports);
38
+ // here we cover the second failure mode — a successfully-imported
39
+ // plugin that throws during construction (bad context lookup, schema
40
+ // build error, composePlugins collision, etc.). Honors the
41
+ // design-doc promise that "a broken extension does not kill the CLI."
42
+ for (const ext of extensions) {
43
+ try {
44
+ chain = chain.addPlugin(ext);
45
+ }
46
+ catch (err) {
47
+ console.warn(`Extension plugin failed to construct: ${err.message}; skipping.`);
48
+ }
49
+ }
50
+ return chain;
28
51
  }
@@ -0,0 +1,20 @@
1
+ import type { Plugin, PluginProvides } from "@zapier/zapier-sdk";
2
+ /**
3
+ * Discovers and dynamically imports SDK extension packages declared via the
4
+ * `ZAPIER_SDK_EXTENSIONS` env var (comma-separated package specifiers).
5
+ * Each spec is `await import()`-ed and its default export is normalized via
6
+ * {@link normalizeExtension}. A failed import or unrecognized export shape
7
+ * triggers a warning and skip — a broken extension never kills the CLI.
8
+ *
9
+ * A richer, declarative discovery path (e.g. `.zapierrc` extensions) is
10
+ * tracked as a follow-up; for now the env var is the only entry point.
11
+ */
12
+ export declare function resolveExtensions(): Promise<Plugin<unknown, PluginProvides>[]>;
13
+ /**
14
+ * Translates a module's default export into a plugin array suitable for
15
+ * `.addPlugin(...)`. Accepts:
16
+ * - a single Plugin function → `[fn]`
17
+ * - an array of Plugin functions → returned as-is
18
+ * Returns `null` for unrecognized shapes (caller emits a skip warning).
19
+ */
20
+ export declare function normalizeExtension(exported: unknown): Plugin<unknown, PluginProvides>[] | null;
@@ -0,0 +1,66 @@
1
+ const ENV_VAR = "ZAPIER_SDK_EXTENSIONS";
2
+ /**
3
+ * Discovers and dynamically imports SDK extension packages declared via the
4
+ * `ZAPIER_SDK_EXTENSIONS` env var (comma-separated package specifiers).
5
+ * Each spec is `await import()`-ed and its default export is normalized via
6
+ * {@link normalizeExtension}. A failed import or unrecognized export shape
7
+ * triggers a warning and skip — a broken extension never kills the CLI.
8
+ *
9
+ * A richer, declarative discovery path (e.g. `.zapierrc` extensions) is
10
+ * tracked as a follow-up; for now the env var is the only entry point.
11
+ */
12
+ export async function resolveExtensions() {
13
+ const seen = new Set();
14
+ const specs = readEnvSpecs().filter((spec) => {
15
+ if (seen.has(spec))
16
+ return false;
17
+ seen.add(spec);
18
+ return true;
19
+ });
20
+ const plugins = [];
21
+ for (const spec of specs) {
22
+ try {
23
+ const mod = await import(spec);
24
+ const exported = mod.default ?? mod;
25
+ const got = normalizeExtension(exported);
26
+ if (got) {
27
+ plugins.push(...got);
28
+ }
29
+ else {
30
+ console.warn(`Extension '${spec}': unrecognized default export shape; skipping.`);
31
+ }
32
+ }
33
+ catch (err) {
34
+ console.warn(`Extension '${spec}' failed to load: ${err.message}`);
35
+ }
36
+ }
37
+ return plugins;
38
+ }
39
+ /**
40
+ * Translates a module's default export into a plugin array suitable for
41
+ * `.addPlugin(...)`. Accepts:
42
+ * - a single Plugin function → `[fn]`
43
+ * - an array of Plugin functions → returned as-is
44
+ * Returns `null` for unrecognized shapes (caller emits a skip warning).
45
+ */
46
+ export function normalizeExtension(exported) {
47
+ if (typeof exported === "function") {
48
+ return [exported];
49
+ }
50
+ if (Array.isArray(exported)) {
51
+ if (exported.every((e) => typeof e === "function")) {
52
+ return exported;
53
+ }
54
+ return null;
55
+ }
56
+ return null;
57
+ }
58
+ function readEnvSpecs() {
59
+ const raw = process.env[ENV_VAR];
60
+ if (!raw)
61
+ return [];
62
+ return raw
63
+ .split(",")
64
+ .map((s) => s.trim())
65
+ .filter((s) => s.length > 0);
66
+ }