@zapier/zapier-sdk 0.6.2 → 0.6.4

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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { existsSync, readFileSync, writeFileSync } from 'fs';
2
+ import { readFileSync, existsSync, writeFileSync } from 'fs';
3
3
  import { resolve } from 'path';
4
4
 
5
5
  // src/types/properties.ts
@@ -318,718 +318,6 @@ var fetchPlugin = ({ sdk }) => {
318
318
  };
319
319
  };
320
320
 
321
- // src/resolvers/appKey.ts
322
- var appKeyResolver = {
323
- type: "static",
324
- inputType: "text",
325
- placeholder: "Enter app key (e.g., 'SlackCLIAPI' or slug like 'github')"
326
- };
327
-
328
- // src/resolvers/actionType.ts
329
- var actionTypeResolver = {
330
- type: "dynamic",
331
- depends: ["appKey"],
332
- fetch: async (sdk, resolvedParams) => {
333
- const actionsResponse = await sdk.listActions({
334
- appKey: resolvedParams.appKey
335
- });
336
- const types = [
337
- ...new Set(actionsResponse.data.map((action) => action.action_type))
338
- ];
339
- return types.map((type) => ({ key: type, name: type }));
340
- },
341
- prompt: (types) => ({
342
- type: "list",
343
- name: "actionType",
344
- message: "Select action type:",
345
- choices: types.map((type) => ({
346
- name: type.name,
347
- value: type.key
348
- }))
349
- })
350
- };
351
-
352
- // src/resolvers/actionKey.ts
353
- var actionKeyResolver = {
354
- type: "dynamic",
355
- depends: ["appKey", "actionType"],
356
- fetch: async (sdk, resolvedParams) => {
357
- const actionsResponse = await sdk.listActions({
358
- appKey: resolvedParams.appKey
359
- });
360
- return actionsResponse.data.filter(
361
- (action) => action.action_type === resolvedParams.actionType
362
- );
363
- },
364
- prompt: (actions) => ({
365
- type: "list",
366
- name: "actionKey",
367
- message: "Select action:",
368
- choices: actions.map((action) => ({
369
- name: `${action.title || action.name || action.key} - ${action.description || "No description"}`,
370
- value: action.key
371
- }))
372
- })
373
- };
374
-
375
- // src/resolvers/authenticationId.ts
376
- var authenticationIdResolver = {
377
- type: "dynamic",
378
- depends: ["appKey"],
379
- fetch: async (sdk, resolvedParams) => {
380
- const myAuths = await sdk.listAuthentications({
381
- appKey: resolvedParams.appKey,
382
- maxItems: 1e3,
383
- owner: "me"
384
- });
385
- const allAuths = await sdk.listAuthentications({
386
- appKey: resolvedParams.appKey,
387
- maxItems: 1e3
388
- });
389
- const otherAuths = allAuths.data.filter(
390
- (auth) => !myAuths.data.some((myAuth) => myAuth.id === auth.id)
391
- );
392
- return [...myAuths.data, ...otherAuths];
393
- },
394
- prompt: (auths, params) => ({
395
- type: "list",
396
- name: "authenticationId",
397
- message: `Select authentication for ${params.appKey}:`,
398
- choices: [
399
- ...auths.map((auth) => ({
400
- name: `${auth.title || auth.label || "Authentication"} (ID: ${auth.id})`,
401
- value: auth.id
402
- })),
403
- {
404
- name: "\u2197 Skip authentication (may fail)",
405
- value: null
406
- }
407
- ]
408
- })
409
- };
410
-
411
- // src/resolvers/inputs.ts
412
- var inputsResolver = {
413
- type: "fields",
414
- depends: ["appKey", "actionKey", "actionType", "authenticationId"],
415
- fetch: async (sdk, resolvedParams) => {
416
- const fieldsResponse = await sdk.listInputFields({
417
- appKey: resolvedParams.appKey,
418
- actionKey: resolvedParams.actionKey,
419
- actionType: resolvedParams.actionType,
420
- authenticationId: resolvedParams.authenticationId,
421
- inputs: resolvedParams.inputs
422
- // Pass along currently resolved inputs
423
- });
424
- return fieldsResponse.data;
425
- }
426
- };
427
-
428
- // src/resolvers/index.ts
429
- var resolverRegistry = {
430
- appKey: appKeyResolver,
431
- actionType: actionTypeResolver,
432
- actionKey: actionKeyResolver,
433
- authenticationId: authenticationIdResolver,
434
- inputs: inputsResolver
435
- };
436
- function getResolver(name) {
437
- return resolverRegistry[name];
438
- }
439
- function getResolversForMissingParams(missingParams) {
440
- const resolvers = {};
441
- for (const param of missingParams) {
442
- const resolver = resolverRegistry[param];
443
- if (resolver) {
444
- resolvers[param] = resolver;
445
- }
446
- }
447
- return resolvers;
448
- }
449
- function hasResolver(paramName) {
450
- return paramName in resolverRegistry;
451
- }
452
- function getResolvableParams() {
453
- return Object.keys(resolverRegistry);
454
- }
455
- function getResolutionOrder(paramName, resolved = /* @__PURE__ */ new Set()) {
456
- const resolver = getResolver(paramName);
457
- if (!resolver || resolver.type === "static") {
458
- return [paramName];
459
- }
460
- const order = [];
461
- if ("depends" in resolver && resolver.depends) {
462
- for (const dependency of resolver.depends) {
463
- if (!resolved.has(dependency)) {
464
- order.push(...getResolutionOrder(dependency, resolved));
465
- resolved.add(dependency);
466
- }
467
- }
468
- }
469
- if (!resolved.has(paramName)) {
470
- order.push(paramName);
471
- resolved.add(paramName);
472
- }
473
- return order;
474
- }
475
- function getResolutionOrderForParams(paramNames) {
476
- const resolved = /* @__PURE__ */ new Set();
477
- const order = [];
478
- for (const paramName of paramNames) {
479
- const paramOrder = getResolutionOrder(paramName, resolved);
480
- for (const param of paramOrder) {
481
- if (!order.includes(param)) {
482
- order.push(param);
483
- }
484
- }
485
- }
486
- return order;
487
- }
488
-
489
- // src/auth.ts
490
- function getTokenFromEnv() {
491
- return process.env.ZAPIER_TOKEN;
492
- }
493
- async function getTokenFromCliLogin(options = {}) {
494
- try {
495
- const { getToken } = await import('@zapier/zapier-sdk-cli-login');
496
- return await getToken(options);
497
- } catch {
498
- return void 0;
499
- }
500
- }
501
- async function getTokenFromEnvOrConfig(options = {}) {
502
- const envToken = getTokenFromEnv();
503
- if (envToken) {
504
- return envToken;
505
- }
506
- return getTokenFromCliLogin(options);
507
- }
508
- var RelayRequestSchema = z.object({
509
- url: z.string().url().describe("The URL to request (will be proxied through Relay)"),
510
- method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]).optional().describe("HTTP method"),
511
- body: z.any().optional().describe("Request body as a string"),
512
- authenticationId: z.number().int().optional().describe("Zapier authentication ID to use for the request"),
513
- callbackUrl: z.string().url().optional().describe("URL to send async response to (makes request async)"),
514
- authenticationTemplate: z.string().optional().describe(
515
- "Optional JSON string authentication template to bypass Notary lookup"
516
- ),
517
- headers: z.union([
518
- z.record(z.string()),
519
- z.instanceof(Headers),
520
- z.array(z.tuple([z.string(), z.string()]))
521
- ]).optional().describe("Request headers")
522
- }).extend({
523
- relayBaseUrl: z.string().optional().describe("Base URL for Relay service")
524
- }).describe("Make authenticated HTTP requests through Zapier's Relay service");
525
- var RelayFetchSchema = RelayRequestSchema;
526
-
527
- // src/plugins/registry/index.ts
528
- var registryPlugin = ({ sdk, context }) => {
529
- const metaKeys = Object.keys(context.meta || {});
530
- const categoryDefinitions = {
531
- app: {
532
- title: "App",
533
- titlePlural: "Apps"
534
- },
535
- authentication: {
536
- title: "Authentication"
537
- },
538
- action: {
539
- title: "Action"
540
- },
541
- http: {
542
- title: "HTTP Request"
543
- },
544
- user: {
545
- title: "User"
546
- },
547
- utility: {
548
- title: "Utility",
549
- titlePlural: "Utilities"
550
- },
551
- other: {
552
- title: "Other"
553
- }
554
- };
555
- const functions = metaKeys.filter((key) => typeof sdk[key] === "function").map((key) => {
556
- return {
557
- ...context.meta[key],
558
- categories: context.meta[key].categories || [],
559
- name: key
560
- };
561
- }).sort((a, b) => a.name.localeCompare(b.name));
562
- const knownCategories = Object.keys(categoryDefinitions);
563
- const categories = knownCategories.sort((a, b) => {
564
- if (a === "other") return 1;
565
- if (b === "other") return -1;
566
- const titleA = categoryDefinitions[a].title;
567
- const titleB = categoryDefinitions[b].title;
568
- return titleA.localeCompare(titleB);
569
- }).map((categoryKey) => {
570
- const categoryFunctions = functions.filter(
571
- (f) => f.categories.includes(categoryKey) || // If the category is "other" and the function is not in any other category, include it
572
- categoryKey === "other" && !f.categories.some((c) => knownCategories.includes(c))
573
- ).map((f) => f.name).sort();
574
- const definition = categoryDefinitions[categoryKey];
575
- const title = definition.title;
576
- return {
577
- key: categoryKey,
578
- title,
579
- titlePlural: definition.titlePlural ?? `${title}s`,
580
- functions: categoryFunctions
581
- };
582
- });
583
- function getRegistry() {
584
- return {
585
- functions,
586
- categories
587
- };
588
- }
589
- return {
590
- getRegistry
591
- };
592
- };
593
-
594
- // src/api/auth.ts
595
- function isJwt(token) {
596
- const parts = token.split(".");
597
- if (parts.length !== 3) {
598
- return false;
599
- }
600
- const base64UrlPattern = /^[A-Za-z0-9_-]+$/;
601
- return parts.every((part) => part.length > 0 && base64UrlPattern.test(part));
602
- }
603
- function getAuthorizationHeader(token) {
604
- if (isJwt(token)) {
605
- return `JWT ${token}`;
606
- }
607
- return `Bearer ${token}`;
608
- }
609
-
610
- // src/api/debug.ts
611
- function createDebugLogger(enabled) {
612
- if (!enabled) {
613
- return () => {
614
- };
615
- }
616
- return (message, data) => {
617
- console.log(`[Zapier SDK] ${message}`, data || "");
618
- };
619
- }
620
- function createDebugFetch(options) {
621
- const { originalFetch, debugLog } = options;
622
- return async (input, options2) => {
623
- const startTime = Date.now();
624
- const url = typeof input === "string" ? input : input.toString();
625
- const method = options2?.method || "GET";
626
- debugLog(`\u2192 ${method} ${url}`, {
627
- headers: options2?.headers,
628
- body: options2?.body && typeof options2.body === "string" ? (() => {
629
- try {
630
- return JSON.parse(options2.body);
631
- } catch {
632
- return options2.body;
633
- }
634
- })() : options2?.body
635
- });
636
- try {
637
- const response = await originalFetch(input, options2);
638
- const duration = Date.now() - startTime;
639
- debugLog(`\u2190 ${response.status} ${response.statusText} (${duration}ms)`, {
640
- url,
641
- method,
642
- status: response.status
643
- });
644
- return response;
645
- } catch (error) {
646
- const duration = Date.now() - startTime;
647
- debugLog(`\u2716 Request failed (${duration}ms)`, {
648
- url,
649
- method,
650
- error: error instanceof Error ? error.message : error
651
- });
652
- throw error;
653
- }
654
- };
655
- }
656
-
657
- // src/api/polling.ts
658
- async function pollUntilComplete(options) {
659
- const {
660
- fetchPoll,
661
- maxAttempts = 30,
662
- initialDelay = 50,
663
- maxDelay = 1e3,
664
- successStatus = 200,
665
- pendingStatus = 202,
666
- resultExtractor = (response) => response
667
- } = options;
668
- let delay = initialDelay;
669
- let errorCount = 0;
670
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
671
- const response = await fetchPoll();
672
- if (response.status === successStatus) {
673
- errorCount = 0;
674
- const result = await response.json();
675
- return resultExtractor(result);
676
- } else if (response.status === pendingStatus) {
677
- errorCount = 0;
678
- if (attempt < maxAttempts - 1) {
679
- await new Promise((resolve3) => setTimeout(resolve3, delay));
680
- delay = Math.min(delay * 2, maxDelay);
681
- continue;
682
- }
683
- } else {
684
- errorCount++;
685
- if (errorCount >= 3) {
686
- throw new ZapierApiError(
687
- `Poll request failed: ${response.status} ${response.statusText}`,
688
- { statusCode: response.status }
689
- );
690
- }
691
- if (attempt < maxAttempts - 1) {
692
- await new Promise((resolve3) => setTimeout(resolve3, delay));
693
- delay = Math.min(delay * 2, maxDelay);
694
- continue;
695
- }
696
- }
697
- }
698
- throw new ZapierTimeoutError(
699
- `Operation timed out after ${maxAttempts} attempts`,
700
- { attempts: maxAttempts, maxAttempts }
701
- );
702
- }
703
-
704
- // src/api/client.ts
705
- var SubdomainConfigMap = {
706
- // e.g. https://relay.zapier.com
707
- relay: {
708
- authHeader: "X-Relay-Authorization"
709
- }
710
- };
711
- var ZapierApiClient = class {
712
- constructor(options) {
713
- this.options = options;
714
- this.fetch = async (path, init) => {
715
- return this.plainFetch(path, init);
716
- };
717
- this.get = async (path, options = {}) => {
718
- return this.fetchJson("GET", path, void 0, options);
719
- };
720
- this.post = async (path, data, options = {}) => {
721
- return this.fetchJson("POST", path, data, options);
722
- };
723
- this.put = async (path, data, options = {}) => {
724
- return this.fetchJson("PUT", path, data, options);
725
- };
726
- this.delete = async (path, options = {}) => {
727
- return this.fetchJson("DELETE", path, void 0, options);
728
- };
729
- this.poll = async (path, options = {}) => {
730
- return pollUntilComplete({
731
- fetchPoll: () => this.plainFetch(path, {
732
- method: "GET",
733
- searchParams: options.searchParams,
734
- authRequired: options.authRequired
735
- }),
736
- maxAttempts: options.maxAttempts,
737
- initialDelay: options.initialDelay,
738
- maxDelay: options.maxDelay,
739
- successStatus: options.successStatus,
740
- pendingStatus: options.pendingStatus,
741
- resultExtractor: options.resultExtractor
742
- });
743
- };
744
- }
745
- // Helper to parse response data
746
- async parseResult(response) {
747
- try {
748
- return { type: "json", data: await response.json() };
749
- } catch {
750
- return { type: "text", data: await response.text() };
751
- }
752
- }
753
- // Helper to get a token from the different places it could be gotten
754
- async getAuthToken() {
755
- if (this.options.token) {
756
- return this.options.token;
757
- }
758
- if (this.options.getToken) {
759
- const token = await this.options.getToken();
760
- if (token) {
761
- return token;
762
- }
763
- }
764
- return getTokenFromEnvOrConfig({
765
- onEvent: this.options.onEvent,
766
- fetch: this.options.fetch
767
- });
768
- }
769
- // Helper to handle responses
770
- async handleResponse(params) {
771
- const { response, customErrorHandler, wasMissingAuthToken } = params;
772
- const { data: responseData } = await this.parseResult(response);
773
- if (response.ok) {
774
- return responseData;
775
- }
776
- const errorInfo = {
777
- status: response.status,
778
- statusText: response.statusText,
779
- data: responseData
780
- };
781
- if (customErrorHandler) {
782
- const customError = customErrorHandler(errorInfo);
783
- if (customError) {
784
- if (customError instanceof Error) {
785
- throw customError;
786
- } else {
787
- throw new Error(
788
- `customErrorHandler returned a non-Error: ${JSON.stringify(customError)}`
789
- );
790
- }
791
- }
792
- }
793
- const { message, errors } = this.parseErrorResponse(errorInfo);
794
- const errorOptions = {
795
- statusCode: response.status,
796
- errors
797
- };
798
- if (response.status === 404) {
799
- throw new ZapierNotFoundError(message, errorOptions);
800
- }
801
- if (response.status === 401 || response.status === 403) {
802
- if (wasMissingAuthToken) {
803
- throw new ZapierAuthenticationError(
804
- `Authentication required (HTTP ${response.status}). Please provide a token in options or set ZAPIER_TOKEN environment variable.`,
805
- errorOptions
806
- );
807
- }
808
- throw new ZapierAuthenticationError(message, errorOptions);
809
- }
810
- if (response.status === 400) {
811
- throw new ZapierValidationError(message, errorOptions);
812
- }
813
- throw new ZapierApiError(message, errorOptions);
814
- }
815
- hasErrorArray(data) {
816
- return typeof data === "object" && data !== null && "errors" in data && Array.isArray(data.errors);
817
- }
818
- // Helper to check if data has API errors
819
- isApiErrorArray(dataArray) {
820
- const data = dataArray[0];
821
- return typeof data === "object" && data !== null && "message" in data && "code" in data && "title" in data && "detail" in data;
822
- }
823
- // Do our best to extract an error message from the response data
824
- extractErrorMessage(data) {
825
- if (typeof data === "string") {
826
- return data;
827
- }
828
- if (typeof data === "object" && data !== null) {
829
- if ("message" in data && typeof data.message === "string") {
830
- return data.message;
831
- }
832
- if ("error" in data) {
833
- if (typeof data.error === "string") {
834
- return data.error;
835
- }
836
- if (typeof data.error === "object" && data.error !== null) {
837
- if ("message" in data.error && typeof data.error.message === "string") {
838
- return data.error.message;
839
- }
840
- }
841
- try {
842
- return JSON.stringify(data.error);
843
- } catch {
844
- }
845
- }
846
- if ("errors" in data && Array.isArray(data.errors)) {
847
- if (this.isApiErrorArray(data.errors)) {
848
- return data.errors[0].detail || data.errors[0].title;
849
- }
850
- }
851
- }
852
- return void 0;
853
- }
854
- // Helper to parse API error response
855
- parseErrorResponse(errorInfo) {
856
- const fallbackMessage = `HTTP ${errorInfo.status}: ${errorInfo.statusText}`;
857
- try {
858
- if (typeof errorInfo.data === "string") {
859
- return { message: `${fallbackMessage}: ${errorInfo.data}` };
860
- }
861
- const errorMessage = this.extractErrorMessage(errorInfo.data) || fallbackMessage;
862
- if (this.hasErrorArray(errorInfo.data)) {
863
- if (this.isApiErrorArray(errorInfo.data.errors)) {
864
- return {
865
- message: errorMessage,
866
- errors: errorInfo.data.errors
867
- };
868
- } else {
869
- return {
870
- message: errorMessage,
871
- errors: errorInfo.data.errors.map((e) => ({
872
- status: errorInfo.status,
873
- code: String(errorInfo.status),
874
- title: errorInfo.statusText,
875
- detail: JSON.stringify(e)
876
- }))
877
- };
878
- }
879
- }
880
- return { message: errorMessage };
881
- } catch {
882
- return { message: fallbackMessage };
883
- }
884
- }
885
- // Check if this is a path that needs subdomain routing
886
- // e.g. /relay/workflows -> relay.zapier.com/workflows
887
- applySubdomainBehavior(path) {
888
- const pathSegments = path.split("/").filter(Boolean);
889
- if (pathSegments.length > 0 && pathSegments[0] in SubdomainConfigMap) {
890
- const domainPrefix = pathSegments[0];
891
- const subdomainConfig = SubdomainConfigMap[domainPrefix];
892
- const originalBaseUrl = new URL(this.options.baseUrl);
893
- const finalBaseUrl = `https://${domainPrefix}.${originalBaseUrl.hostname}`;
894
- const pathWithoutPrefix = "/" + pathSegments.slice(1).join("/");
895
- return { url: new URL(pathWithoutPrefix, finalBaseUrl), subdomainConfig };
896
- }
897
- return {
898
- url: new URL(path, this.options.baseUrl),
899
- subdomainConfig: void 0
900
- };
901
- }
902
- // Helper to build full URLs and return routing info
903
- buildUrl(path, searchParams) {
904
- const { url, subdomainConfig } = this.applySubdomainBehavior(path);
905
- if (searchParams) {
906
- Object.entries(searchParams).forEach(([key, value]) => {
907
- url.searchParams.set(key, value);
908
- });
909
- }
910
- return { url: url.toString(), subdomainConfig };
911
- }
912
- // Helper to build headers
913
- async buildHeaders(options = {}, subdomainConfig) {
914
- const headers = new Headers(options.headers ?? {});
915
- const authToken = await this.getAuthToken();
916
- if (authToken) {
917
- const authHeaderName = subdomainConfig?.authHeader || "Authorization";
918
- headers.set(authHeaderName, getAuthorizationHeader(authToken));
919
- }
920
- if (options.authRequired) {
921
- if (headers.get("Authorization") == null && authToken == null) {
922
- throw new ZapierAuthenticationError(
923
- `Authentication required but no token available. Please set ZAPIER_TOKEN, or run the 'login' command with the CLI.`
924
- );
925
- }
926
- }
927
- return headers;
928
- }
929
- // Helper to perform HTTP requests with JSON handling
930
- async fetchJson(method, path, data, options = {}) {
931
- const headers = { ...options.headers };
932
- if (data && typeof data === "object") {
933
- headers["Content-Type"] = "application/json";
934
- }
935
- const wasMissingAuthToken = options.authRequired && await this.getAuthToken() == null;
936
- const response = await this.plainFetch(path, {
937
- ...options,
938
- method,
939
- body: data != null ? JSON.stringify(data) : void 0,
940
- headers
941
- });
942
- const result = await this.handleResponse({
943
- response,
944
- customErrorHandler: options.customErrorHandler,
945
- wasMissingAuthToken
946
- });
947
- if (typeof result === "string") {
948
- throw new ZapierValidationError(
949
- `Response could not be parsed as JSON: ${result}`
950
- );
951
- }
952
- return result;
953
- }
954
- // Plain fetch method for API paths (must start with /)
955
- async plainFetch(path, fetchOptions) {
956
- if (!path.startsWith("/")) {
957
- throw new ZapierValidationError(
958
- `plainFetch expects a path starting with '/', got: ${path}`
959
- );
960
- }
961
- if (fetchOptions?.body && typeof fetchOptions.body === "object") {
962
- fetchOptions.body = JSON.stringify(fetchOptions.body);
963
- }
964
- const { url, subdomainConfig } = this.buildUrl(
965
- path,
966
- fetchOptions?.searchParams
967
- );
968
- const builtHeaders = await this.buildHeaders(
969
- fetchOptions,
970
- subdomainConfig
971
- );
972
- const inputHeaders = new Headers(fetchOptions?.headers ?? {});
973
- const mergedHeaders = new Headers();
974
- builtHeaders.forEach((value, key) => {
975
- mergedHeaders.set(key, value);
976
- });
977
- inputHeaders.forEach((value, key) => {
978
- mergedHeaders.set(key, value);
979
- });
980
- return await this.options.fetch(url, {
981
- ...fetchOptions,
982
- headers: mergedHeaders
983
- });
984
- }
985
- };
986
- var createZapierApi = (options) => {
987
- const {
988
- baseUrl,
989
- token,
990
- getToken,
991
- debug = false,
992
- fetch: originalFetch = globalThis.fetch,
993
- onEvent
994
- } = options;
995
- const debugLog = createDebugLogger(debug);
996
- const debugFetch = createDebugFetch({ originalFetch, debugLog });
997
- return new ZapierApiClient({
998
- baseUrl,
999
- token,
1000
- getToken,
1001
- debug,
1002
- fetch: debugFetch,
1003
- onEvent
1004
- });
1005
- };
1006
-
1007
- // src/plugins/api/index.ts
1008
- var apiPlugin = (params) => {
1009
- const {
1010
- fetch: customFetch = globalThis.fetch,
1011
- baseUrl = "https://zapier.com",
1012
- token,
1013
- getToken,
1014
- onEvent,
1015
- debug = false
1016
- } = params.context.options;
1017
- const api = createZapierApi({
1018
- baseUrl,
1019
- token,
1020
- getToken,
1021
- debug,
1022
- fetch: customFetch,
1023
- onEvent
1024
- });
1025
- return {
1026
- context: {
1027
- api
1028
- // Provide API client in context for other plugins to use
1029
- }
1030
- };
1031
- };
1032
-
1033
321
  // src/utils/pagination-utils.ts
1034
322
  var offsetCursorMarker = "$$offset$$";
1035
323
  function splitOffsetCursor(cursor) {
@@ -1310,11 +598,261 @@ function createPaginatedFunction(coreFn, schema) {
1310
598
  }
1311
599
  };
1312
600
  }
1313
- });
601
+ });
602
+ }
603
+ };
604
+ return namedFunctions[functionName];
605
+ }
606
+ var AppItemSchema = withFormatter(
607
+ z.object({
608
+ // Essential properties only
609
+ title: z.string(),
610
+ // Mapped from name
611
+ key: z.string(),
612
+ // Mapped from selected_api
613
+ current_implementation_id: z.string(),
614
+ // From id, keeps the full version
615
+ version: z.string().optional(),
616
+ // Extracted from implementation ID
617
+ description: z.string().optional(),
618
+ slug: z.string().optional()
619
+ }),
620
+ {
621
+ format: (item) => {
622
+ return {
623
+ title: item.title,
624
+ subtitle: `(${item.key})`,
625
+ details: []
626
+ };
627
+ }
628
+ }
629
+ );
630
+
631
+ // src/plugins/listApps/schemas.ts
632
+ var ListAppsSchema = withOutputSchema(
633
+ z.object({
634
+ appKeys: z.array(z.string()).optional().describe(
635
+ "Filter apps by app keys (e.g., 'SlackCLIAPI' or slug like 'github')"
636
+ ),
637
+ search: z.string().optional().describe("Search for apps by name"),
638
+ pageSize: z.number().min(1).optional().describe("Number of apps per page"),
639
+ maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages")
640
+ }).describe("List all available apps with optional filtering"),
641
+ AppItemSchema
642
+ );
643
+
644
+ // src/utils/domain-utils.ts
645
+ function splitVersionedKey(versionedKey) {
646
+ const parts = versionedKey.split("@");
647
+ if (parts.length >= 2) {
648
+ const baseKey = parts[0];
649
+ const version = parts.slice(1).join("@");
650
+ return [baseKey, version];
651
+ }
652
+ return [versionedKey, void 0];
653
+ }
654
+ function normalizeImplementationToAppItem(implementation) {
655
+ const [selectedApi, appVersion] = implementation.selected_api ? splitVersionedKey(implementation.selected_api) : [implementation.selected_api || "", void 0];
656
+ return {
657
+ title: implementation.name || selectedApi,
658
+ key: selectedApi,
659
+ current_implementation_id: implementation.selected_api || "",
660
+ version: appVersion
661
+ // Extract version separately
662
+ };
663
+ }
664
+ function normalizeImplementationMetaToAppItem(implementationMeta) {
665
+ const [selectedApi, appVersion] = splitVersionedKey(implementationMeta.id);
666
+ return {
667
+ title: implementationMeta.name,
668
+ key: selectedApi,
669
+ current_implementation_id: implementationMeta.id,
670
+ // Keep the full versioned ID
671
+ version: appVersion,
672
+ // Extract version separately
673
+ slug: implementationMeta.slug
674
+ };
675
+ }
676
+ function normalizeAuthenticationItem(auth, options = {}) {
677
+ let appKey = options.app_key;
678
+ let version = options.version;
679
+ if (auth.selected_api) {
680
+ const [extractedAppKey, extractedVersion] = splitVersionedKey(
681
+ auth.selected_api
682
+ );
683
+ if (!appKey) {
684
+ appKey = extractedAppKey;
685
+ }
686
+ if (!version) {
687
+ version = extractedVersion;
688
+ }
689
+ }
690
+ const {
691
+ selected_api: selectedApi,
692
+ customuser_id: userId,
693
+ ...restOfAuth
694
+ } = auth;
695
+ return {
696
+ ...restOfAuth,
697
+ // Pass through all other API response fields except selected_api
698
+ implementation_id: selectedApi,
699
+ // Rename selected_api to implementation_id
700
+ title: auth.title || auth.label || void 0,
701
+ // Coerce title from label if missing
702
+ is_expired: auth.is_stale,
703
+ // Map is_stale to is_expired
704
+ expired_at: auth.marked_stale_at,
705
+ // Map marked_stale_at to expired_at
706
+ app_key: appKey,
707
+ // App key from implementations endpoint or parsed from selected_api
708
+ version,
709
+ // Version from selected_api or provided
710
+ user_id: userId
711
+ // Map customuser_id to user_id
712
+ };
713
+ }
714
+ function normalizeActionItem(action) {
715
+ const { name, type, selected_api: appKey, ...restOfAction } = action;
716
+ return {
717
+ ...restOfAction,
718
+ app_key: appKey || "",
719
+ action_type: type,
720
+ title: name,
721
+ // Map name to title
722
+ type: "action"
723
+ };
724
+ }
725
+ function groupVersionedAppKeysByType(appKeys) {
726
+ const result = {
727
+ selectedApi: [],
728
+ slug: []
729
+ };
730
+ const seenSelectedApi = /* @__PURE__ */ new Set();
731
+ const seenSlugs = /* @__PURE__ */ new Set();
732
+ for (const key of appKeys) {
733
+ const [keyWithoutVersion, version] = splitVersionedKey(key);
734
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
735
+ if (uuidRegex.test(keyWithoutVersion)) {
736
+ throw new Error(
737
+ `UUID app keys are not supported. Use app slug or implementation ID instead of: ${key}`
738
+ );
739
+ }
740
+ if (isSnakeCasedSlug(keyWithoutVersion)) {
741
+ const dashified = dashifySnakeCasedSlug(keyWithoutVersion);
742
+ const slugWithVersion = version ? `${dashified}@${version}` : dashified;
743
+ if (!seenSlugs.has(slugWithVersion)) {
744
+ seenSlugs.add(slugWithVersion);
745
+ result.slug.push(slugWithVersion);
746
+ }
747
+ continue;
748
+ }
749
+ if (keyWithoutVersion.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)) {
750
+ seenSlugs.add(key);
751
+ result.slug.push(key);
752
+ continue;
753
+ }
754
+ if (!seenSelectedApi.has(key)) {
755
+ seenSelectedApi.add(key);
756
+ result.selectedApi.push(key);
757
+ }
758
+ }
759
+ return result;
760
+ }
761
+ function groupAppKeysByType(appKeys) {
762
+ const grouped = groupVersionedAppKeysByType(appKeys);
763
+ return {
764
+ selectedApi: [
765
+ ...new Set(grouped.selectedApi.map((key) => key.split("@")[0]))
766
+ ],
767
+ slug: [...new Set(grouped.slug.map((key) => key.split("@")[0]))]
768
+ };
769
+ }
770
+ function isSnakeCasedSlug(slug) {
771
+ if (slug.match(/^_[0-9]/)) {
772
+ slug = slug.slice(1);
773
+ }
774
+ return !!slug.match(/^[a-z0-9]+(?:_[a-z0-9]+)*$/);
775
+ }
776
+ function dashifySnakeCasedSlug(slug) {
777
+ if (!isSnakeCasedSlug(slug)) {
778
+ return slug;
779
+ }
780
+ if (slug.startsWith("_")) {
781
+ slug = slug.slice(1);
782
+ }
783
+ return slug.replace(/_/g, "-");
784
+ }
785
+
786
+ // src/plugins/listApps/index.ts
787
+ var listAppsPlugin = ({ context }) => {
788
+ const listApps = createPaginatedFunction(async function listAppsPage(options) {
789
+ const api = context.api;
790
+ const opts = options;
791
+ const appKeys = [...opts.appKeys ?? []].map(
792
+ (key) => splitVersionedKey(key)[0]
793
+ );
794
+ if (opts.search) {
795
+ const searchParams2 = {};
796
+ searchParams2.term = opts.search;
797
+ const searchEnvelope = await api.get(
798
+ "/api/v4/implementations-meta/search/",
799
+ {
800
+ searchParams: searchParams2
801
+ }
802
+ );
803
+ const implementations = searchEnvelope.results.map(
804
+ normalizeImplementationMetaToAppItem
805
+ );
806
+ const appKeysSet = new Set(appKeys);
807
+ for (const implementation of implementations) {
808
+ if (!appKeysSet.has(implementation.key)) {
809
+ appKeysSet.add(implementation.key);
810
+ appKeys.push(implementation.key);
811
+ }
812
+ }
813
+ }
814
+ const searchParams = {};
815
+ if (opts.pageSize) {
816
+ searchParams.limit = opts.pageSize.toString();
817
+ }
818
+ searchParams.latest_only = "true";
819
+ if (opts.cursor) {
820
+ searchParams.offset = opts.cursor;
821
+ }
822
+ if (appKeys.length > 0) {
823
+ const groupedAppKeys = groupAppKeysByType(appKeys);
824
+ if (groupedAppKeys.selectedApi.length > 0) {
825
+ searchParams.selected_apis = groupedAppKeys.selectedApi.join(",");
826
+ }
827
+ if (groupedAppKeys.slug.length > 0) {
828
+ searchParams.slugs = groupedAppKeys.slug.join(",");
829
+ }
830
+ }
831
+ const implementationsEnvelope = await api.get(
832
+ "/api/v4/implementations-meta/lookup/",
833
+ {
834
+ searchParams
835
+ }
836
+ );
837
+ return {
838
+ data: implementationsEnvelope.results.map(
839
+ normalizeImplementationMetaToAppItem
840
+ ),
841
+ nextCursor: extractCursor(implementationsEnvelope)
842
+ };
843
+ }, ListAppsSchema);
844
+ return {
845
+ listApps,
846
+ context: {
847
+ meta: {
848
+ listApps: {
849
+ categories: ["app"],
850
+ inputSchema: ListAppsSchema
851
+ }
852
+ }
1314
853
  }
1315
854
  };
1316
- return namedFunctions[functionName];
1317
- }
855
+ };
1318
856
  var NeedChoicesSchema = z.object({
1319
857
  key: z.string().optional(),
1320
858
  label: z.string().optional(),
@@ -1650,314 +1188,337 @@ z.object({
1650
1188
  results: z.array(ImplementationMetaSchema)
1651
1189
  });
1652
1190
 
1653
- // src/schemas/UserProfile.ts
1654
- var UserProfileItemSchema = withFormatter(
1655
- UserProfileSchema.omit({ user_id: true }).extend({
1656
- full_name: z.string()
1657
- // Computed field: first_name + " " + last_name
1191
+ // src/schemas/Action.ts
1192
+ var ActionItemSchema = withFormatter(
1193
+ ActionSchema.omit({ type: true, name: true }).extend({
1194
+ app_key: z.string(),
1195
+ // Mapped from selected_api
1196
+ action_type: ActionSchema.shape.type,
1197
+ // Mapped from original 'type' field
1198
+ title: z.string(),
1199
+ // Mapped from original 'name' field
1200
+ type: z.literal("action")
1201
+ // Fixed type identifier
1658
1202
  }),
1659
1203
  {
1660
1204
  format: (item) => {
1661
1205
  const details = [];
1662
- details.push({ text: item.email, style: "dim" });
1663
- if (item.timezone) {
1664
- details.push({
1665
- text: `Timezone: ${item.timezone}`,
1666
- style: "accent"
1667
- });
1668
- }
1669
1206
  details.push({
1670
- text: `Member since: ${item.since_signup}`,
1671
- style: "dim"
1207
+ text: `Type: ${item.action_type}`,
1208
+ style: "accent"
1672
1209
  });
1673
- return {
1674
- title: item.full_name,
1675
- subtitle: `@${item.username}`,
1676
- details
1677
- };
1678
- }
1679
- }
1680
- );
1681
-
1682
- // src/plugins/getProfile/schemas.ts
1683
- var GetProfileSchema = withOutputSchema(
1684
- z.object({}).optional().describe("Get current user's profile information"),
1685
- UserProfileItemSchema
1686
- );
1687
-
1688
- // src/plugins/getProfile/index.ts
1689
- var getProfilePlugin = ({ context }) => {
1690
- const getProfile = createFunction(async function getProfile2() {
1691
- const profile = await context.api.get("/api/v4/profile/", {
1692
- authRequired: true
1693
- });
1694
- const { user_id: _unusedUserId, ...data } = profile;
1695
- return {
1696
- data: {
1697
- ...data,
1698
- // Pass through all API response fields
1699
- full_name: `${profile.first_name} ${profile.last_name}`
1700
- // Computed field
1210
+ if (item.app_key) {
1211
+ details.push({
1212
+ text: `App: ${item.app_key}`,
1213
+ style: "normal"
1214
+ });
1701
1215
  }
1702
- };
1703
- }, GetProfileSchema);
1704
- return {
1705
- getProfile,
1706
- context: {
1707
- meta: {
1708
- getProfile: {
1709
- categories: ["user"],
1710
- inputSchema: GetProfileSchema
1711
- }
1216
+ if (item.description) {
1217
+ details.push({ text: item.description, style: "dim" });
1712
1218
  }
1713
- }
1714
- };
1715
- };
1716
- var AppItemSchema = withFormatter(
1717
- z.object({
1718
- // Essential properties only
1719
- title: z.string(),
1720
- // Mapped from name
1721
- key: z.string(),
1722
- // Mapped from selected_api
1723
- current_implementation_id: z.string(),
1724
- // From id, keeps the full version
1725
- version: z.string().optional(),
1726
- // Extracted from implementation ID
1727
- description: z.string().optional(),
1728
- slug: z.string().optional()
1729
- }),
1730
- {
1731
- format: (item) => {
1732
1219
  return {
1733
- title: item.title,
1220
+ title: item.title || item.name || item.key,
1734
1221
  subtitle: `(${item.key})`,
1735
- details: []
1222
+ details
1736
1223
  };
1737
1224
  }
1738
1225
  }
1739
1226
  );
1740
1227
 
1741
- // src/plugins/listApps/schemas.ts
1742
- var ListAppsSchema = withOutputSchema(
1228
+ // src/plugins/listActions/schemas.ts
1229
+ var ListActionsSchema = withOutputSchema(
1743
1230
  z.object({
1744
- appKeys: z.array(z.string()).optional().describe(
1745
- "Filter apps by app keys (e.g., 'SlackCLIAPI' or slug like 'github')"
1231
+ appKey: AppKeyPropertySchema.describe(
1232
+ "App key of actions to list (e.g., 'SlackCLIAPI')"
1746
1233
  ),
1747
- search: z.string().optional().describe("Search for apps by name"),
1748
- pageSize: z.number().min(1).optional().describe("Number of apps per page"),
1234
+ actionType: ActionTypePropertySchema.optional().describe(
1235
+ "Filter actions by type"
1236
+ ),
1237
+ pageSize: z.number().min(1).optional().describe("Number of actions per page"),
1749
1238
  maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages")
1750
- }).describe("List all available apps with optional filtering"),
1751
- AppItemSchema
1239
+ }).describe("List all actions for a specific app"),
1240
+ ActionItemSchema
1752
1241
  );
1753
1242
 
1754
- // src/utils/domain-utils.ts
1755
- function splitVersionedKey(versionedKey) {
1756
- const parts = versionedKey.split("@");
1757
- if (parts.length >= 2) {
1758
- const baseKey = parts[0];
1759
- const version = parts.slice(1).join("@");
1760
- return [baseKey, version];
1761
- }
1762
- return [versionedKey, void 0];
1763
- }
1764
- function normalizeImplementationToAppItem(implementation) {
1765
- const [selectedApi, appVersion] = implementation.selected_api ? splitVersionedKey(implementation.selected_api) : [implementation.selected_api || "", void 0];
1766
- return {
1767
- title: implementation.name || selectedApi,
1768
- key: selectedApi,
1769
- current_implementation_id: implementation.selected_api || "",
1770
- version: appVersion
1771
- // Extract version separately
1772
- };
1773
- }
1774
- function normalizeImplementationMetaToAppItem(implementationMeta) {
1775
- const [selectedApi, appVersion] = splitVersionedKey(implementationMeta.id);
1776
- return {
1777
- title: implementationMeta.name,
1778
- key: selectedApi,
1779
- current_implementation_id: implementationMeta.id,
1780
- // Keep the full versioned ID
1781
- version: appVersion,
1782
- // Extract version separately
1783
- slug: implementationMeta.slug
1784
- };
1785
- }
1786
- function normalizeAuthenticationItem(auth, options = {}) {
1787
- let appKey = options.app_key;
1788
- let version = options.version;
1789
- if (auth.selected_api) {
1790
- const [extractedAppKey, extractedVersion] = splitVersionedKey(
1791
- auth.selected_api
1792
- );
1793
- if (!appKey) {
1794
- appKey = extractedAppKey;
1795
- }
1796
- if (!version) {
1797
- version = extractedVersion;
1798
- }
1799
- }
1800
- const {
1801
- selected_api: selectedApi,
1802
- customuser_id: userId,
1803
- ...restOfAuth
1804
- } = auth;
1805
- return {
1806
- ...restOfAuth,
1807
- // Pass through all other API response fields except selected_api
1808
- implementation_id: selectedApi,
1809
- // Rename selected_api to implementation_id
1810
- title: auth.title || auth.label || void 0,
1811
- // Coerce title from label if missing
1812
- is_expired: auth.is_stale,
1813
- // Map is_stale to is_expired
1814
- expired_at: auth.marked_stale_at,
1815
- // Map marked_stale_at to expired_at
1816
- app_key: appKey,
1817
- // App key from implementations endpoint or parsed from selected_api
1818
- version,
1819
- // Version from selected_api or provided
1820
- user_id: userId
1821
- // Map customuser_id to user_id
1822
- };
1823
- }
1824
- function normalizeActionItem(action) {
1825
- const { name, type, selected_api: appKey, ...restOfAction } = action;
1826
- return {
1827
- ...restOfAction,
1828
- app_key: appKey || "",
1829
- action_type: type,
1830
- title: name,
1831
- // Map name to title
1832
- type: "action"
1833
- };
1834
- }
1835
- function groupVersionedAppKeysByType(appKeys) {
1836
- const result = {
1837
- selectedApi: [],
1838
- slug: []
1839
- };
1840
- const seenSelectedApi = /* @__PURE__ */ new Set();
1841
- const seenSlugs = /* @__PURE__ */ new Set();
1842
- for (const key of appKeys) {
1843
- const [keyWithoutVersion, version] = splitVersionedKey(key);
1844
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1845
- if (uuidRegex.test(keyWithoutVersion)) {
1846
- throw new Error(
1847
- `UUID app keys are not supported. Use app slug or implementation ID instead of: ${key}`
1243
+ // src/plugins/listActions/index.ts
1244
+ var listActionsPlugin = ({ context }) => {
1245
+ const listActions = createPaginatedFunction(async function listActionsPage(options) {
1246
+ const { api, getVersionedImplementationId } = context;
1247
+ const selectedApi = await getVersionedImplementationId(options.appKey);
1248
+ if (!selectedApi) {
1249
+ throw new ZapierConfigurationError(
1250
+ "No current_implementation_id found for app",
1251
+ { configType: "current_implementation_id" }
1848
1252
  );
1849
1253
  }
1850
- if (isSnakeCasedSlug(keyWithoutVersion)) {
1851
- const dashified = dashifySnakeCasedSlug(keyWithoutVersion);
1852
- const slugWithVersion = version ? `${dashified}@${version}` : dashified;
1853
- if (!seenSlugs.has(slugWithVersion)) {
1854
- seenSlugs.add(slugWithVersion);
1855
- result.slug.push(slugWithVersion);
1254
+ const searchParams = {
1255
+ global: "true",
1256
+ public_only: "true",
1257
+ selected_apis: selectedApi
1258
+ };
1259
+ const data = await api.get(
1260
+ "/api/v4/implementations/",
1261
+ {
1262
+ searchParams,
1263
+ customErrorHandler: ({ status }) => {
1264
+ if (status === 401) {
1265
+ return new ZapierAuthenticationError(
1266
+ `Authentication failed. Your token may not have permission to access implementations or may be expired. (HTTP ${status})`,
1267
+ { statusCode: status }
1268
+ );
1269
+ }
1270
+ if (status === 403) {
1271
+ return new ZapierAuthenticationError(
1272
+ `Access forbidden. Your token may not have the required scopes to list implementations. (HTTP ${status})`,
1273
+ { statusCode: status }
1274
+ );
1275
+ }
1276
+ return void 0;
1277
+ }
1278
+ }
1279
+ );
1280
+ let allActions = [];
1281
+ for (const implementation of data.results || []) {
1282
+ if (implementation.actions) {
1283
+ for (const action of implementation.actions) {
1284
+ const actionWithContext = {
1285
+ ...action,
1286
+ selected_api: action.selected_api || implementation.selected_api
1287
+ };
1288
+ allActions.push(normalizeActionItem(actionWithContext));
1289
+ }
1856
1290
  }
1857
- continue;
1858
1291
  }
1859
- if (keyWithoutVersion.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)) {
1860
- seenSlugs.add(key);
1861
- result.slug.push(key);
1862
- continue;
1292
+ if (options.actionType) {
1293
+ allActions = allActions.filter(
1294
+ (action) => action.action_type === options.actionType
1295
+ );
1863
1296
  }
1864
- if (!seenSelectedApi.has(key)) {
1865
- seenSelectedApi.add(key);
1866
- result.selectedApi.push(key);
1297
+ return {
1298
+ data: allActions,
1299
+ nextCursor: void 0
1300
+ };
1301
+ }, ListActionsSchema);
1302
+ return {
1303
+ listActions,
1304
+ context: {
1305
+ meta: {
1306
+ listActions: {
1307
+ categories: ["action"],
1308
+ inputSchema: ListActionsSchema
1309
+ }
1310
+ }
1867
1311
  }
1312
+ };
1313
+ };
1314
+ var ListInputFieldsSchema = z.object({
1315
+ appKey: AppKeyPropertySchema,
1316
+ actionType: ActionTypePropertySchema,
1317
+ actionKey: ActionKeyPropertySchema,
1318
+ authenticationId: AuthenticationIdPropertySchema.nullable().optional(),
1319
+ inputs: InputsPropertySchema.optional().describe(
1320
+ "Current input values that may affect available fields"
1321
+ ),
1322
+ pageSize: z.number().min(1).optional().describe("Number of input fields per page"),
1323
+ maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages")
1324
+ }).describe("Get the input fields required for a specific action");
1325
+
1326
+ // src/plugins/listInputFields/index.ts
1327
+ function getInputFieldTypeFromNeed(need) {
1328
+ if (need.list) {
1329
+ return "ARRAY" /* ARRAY */;
1868
1330
  }
1869
- return result;
1870
- }
1871
- function groupAppKeysByType(appKeys) {
1872
- const grouped = groupVersionedAppKeysByType(appKeys);
1873
- return {
1874
- selectedApi: [
1875
- ...new Set(grouped.selectedApi.map((key) => key.split("@")[0]))
1876
- ],
1877
- slug: [...new Set(grouped.slug.map((key) => key.split("@")[0]))]
1331
+ const typeMap = {
1332
+ string: "STRING" /* STRING */,
1333
+ decimal: "NUMBER" /* NUMBER */,
1334
+ integer: "INTEGER" /* INTEGER */,
1335
+ boolean: "BOOLEAN" /* BOOLEAN */,
1336
+ dict: "OBJECT" /* OBJECT */
1878
1337
  };
1338
+ return typeMap[need.type || ""] || "STRING" /* STRING */;
1879
1339
  }
1880
- function isSnakeCasedSlug(slug) {
1881
- if (slug.match(/^_[0-9]/)) {
1882
- slug = slug.slice(1);
1340
+ function getInputFieldFormatFromNeed(need) {
1341
+ if (need.prefill || need.choices) {
1342
+ return "SELECT" /* SELECT */;
1883
1343
  }
1884
- return !!slug.match(/^[a-z0-9]+(?:_[a-z0-9]+)*$/);
1344
+ const formatMap = {
1345
+ text: "MULTILINE" /* MULTILINE */,
1346
+ datetime: "DATETIME" /* DATETIME */,
1347
+ file: "FILE" /* FILE */,
1348
+ password: "PASSWORD" /* PASSWORD */,
1349
+ code: "CODE" /* CODE */
1350
+ };
1351
+ return formatMap[need.type || ""];
1885
1352
  }
1886
- function dashifySnakeCasedSlug(slug) {
1887
- if (!isSnakeCasedSlug(slug)) {
1888
- return slug;
1889
- }
1890
- if (slug.startsWith("_")) {
1891
- slug = slug.slice(1);
1353
+ function getItemsTypeFromNeed(need) {
1354
+ if (!need.list) {
1355
+ return void 0;
1892
1356
  }
1893
- return slug.replace(/_/g, "-");
1357
+ const typeMap = {
1358
+ string: "STRING" /* STRING */,
1359
+ decimal: "NUMBER" /* NUMBER */,
1360
+ integer: "INTEGER" /* INTEGER */,
1361
+ boolean: "BOOLEAN" /* BOOLEAN */,
1362
+ dict: "OBJECT" /* OBJECT */
1363
+ };
1364
+ return typeMap[need.type || ""] || "STRING" /* STRING */;
1894
1365
  }
1895
-
1896
- // src/plugins/listApps/index.ts
1897
- var listAppsPlugin = ({ context }) => {
1898
- const listApps = createPaginatedFunction(async function listAppsPage(options) {
1899
- const api = context.api;
1900
- const opts = options;
1901
- const appKeys = [...opts.appKeys ?? []].map(
1902
- (key) => splitVersionedKey(key)[0]
1903
- );
1904
- if (opts.search) {
1905
- const searchParams2 = {};
1906
- searchParams2.term = opts.search;
1907
- const searchEnvelope = await api.get(
1908
- "/api/v4/implementations-meta/search/",
1909
- {
1910
- searchParams: searchParams2
1911
- }
1366
+ function transformNeedToInputFieldItem(need) {
1367
+ const itemsType = getItemsTypeFromNeed(need);
1368
+ return {
1369
+ ...need,
1370
+ // Pass through all original Need fields
1371
+ id: need.key,
1372
+ default_value: need.default || "",
1373
+ depends_on: need.depends_on || [],
1374
+ description: need.help_text || "",
1375
+ invalidates_input_fields: need.alters_custom_fields || false,
1376
+ is_required: need.required || false,
1377
+ placeholder: need.placeholder || "",
1378
+ title: need.label || "",
1379
+ value_type: getInputFieldTypeFromNeed(need),
1380
+ format: getInputFieldFormatFromNeed(need),
1381
+ items: itemsType ? { type: itemsType } : void 0
1382
+ };
1383
+ }
1384
+ var listInputFieldsPlugin = ({ context }) => {
1385
+ const listInputFields = createPaginatedFunction(
1386
+ async function listInputFieldsPage(options) {
1387
+ const { api, getVersionedImplementationId } = context;
1388
+ const { appKey, actionKey, actionType, authenticationId, inputs } = options;
1389
+ const selectedApi = await getVersionedImplementationId(appKey);
1390
+ if (!selectedApi) {
1391
+ throw new ZapierConfigurationError(
1392
+ "No current_implementation_id found for app",
1393
+ { configType: "current_implementation_id" }
1394
+ );
1395
+ }
1396
+ const needsRequest = {
1397
+ selected_api: selectedApi,
1398
+ action: actionKey,
1399
+ type_of: actionType,
1400
+ params: inputs || {}
1401
+ };
1402
+ if (authenticationId !== null) {
1403
+ needsRequest.authentication_id = authenticationId;
1404
+ }
1405
+ const needsData = await api.post(
1406
+ "/api/v4/implementations/needs/",
1407
+ needsRequest
1912
1408
  );
1913
- const implementations = searchEnvelope.results.map(
1914
- normalizeImplementationMetaToAppItem
1409
+ if (!needsData.success) {
1410
+ throw new ZapierApiError(
1411
+ `Failed to get action fields: ${needsData.errors?.join(", ") || "Unknown error"}`
1412
+ );
1413
+ }
1414
+ const inputFields = (needsData.needs || []).map(
1415
+ transformNeedToInputFieldItem
1915
1416
  );
1916
- const appKeysSet = new Set(appKeys);
1917
- for (const implementation of implementations) {
1918
- if (!appKeysSet.has(implementation.key)) {
1919
- appKeysSet.add(implementation.key);
1920
- appKeys.push(implementation.key);
1417
+ return {
1418
+ data: inputFields,
1419
+ nextCursor: void 0
1420
+ // No pagination needed since we return all input fields
1421
+ };
1422
+ },
1423
+ ListInputFieldsSchema
1424
+ );
1425
+ return {
1426
+ listInputFields,
1427
+ context: {
1428
+ meta: {
1429
+ listInputFields: {
1430
+ categories: ["action"],
1431
+ inputSchema: ListInputFieldsSchema
1921
1432
  }
1922
1433
  }
1923
1434
  }
1924
- const searchParams = {};
1925
- if (opts.pageSize) {
1926
- searchParams.limit = opts.pageSize.toString();
1927
- }
1928
- searchParams.latest_only = "true";
1929
- if (opts.cursor) {
1930
- searchParams.offset = opts.cursor;
1931
- }
1932
- if (appKeys.length > 0) {
1933
- const groupedAppKeys = groupAppKeysByType(appKeys);
1934
- if (groupedAppKeys.selectedApi.length > 0) {
1935
- searchParams.selected_apis = groupedAppKeys.selectedApi.join(",");
1435
+ };
1436
+ };
1437
+ var ListAuthenticationsSchema = z.object({
1438
+ appKey: AppKeyPropertySchema.optional().describe(
1439
+ "App key of authentications to list (e.g., 'SlackCLIAPI')"
1440
+ ),
1441
+ search: z.string().optional().describe("Search term to filter authentications by title"),
1442
+ title: z.string().optional().describe("Filter authentications by exact title match"),
1443
+ account_id: z.string().optional().describe("Filter by account ID"),
1444
+ owner: z.string().optional().describe("Filter by owner"),
1445
+ pageSize: z.number().min(1).optional().describe("Number of authentications per page"),
1446
+ maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages")
1447
+ }).describe("List available authentications with optional filtering");
1448
+
1449
+ // src/plugins/listAuthentications/index.ts
1450
+ var listAuthenticationsPlugin = ({ context }) => {
1451
+ const listAuthentications = createPaginatedFunction(
1452
+ async function listAuthenticationsPage(options) {
1453
+ const { api, getVersionedImplementationId } = context;
1454
+ const searchParams = {};
1455
+ if (options.appKey) {
1456
+ const implementationId = await getVersionedImplementationId(
1457
+ options.appKey
1458
+ );
1459
+ if (implementationId) {
1460
+ const [versionlessSelectedApi] = splitVersionedKey(implementationId);
1461
+ searchParams.versionless_selected_api = versionlessSelectedApi;
1462
+ }
1936
1463
  }
1937
- if (groupedAppKeys.slug.length > 0) {
1938
- searchParams.slugs = groupedAppKeys.slug.join(",");
1464
+ if (options.search) {
1465
+ searchParams.search = options.search;
1466
+ } else if (options.title) {
1467
+ searchParams.search = options.title;
1939
1468
  }
1940
- }
1941
- const implementationsEnvelope = await api.get(
1942
- "/api/v4/implementations-meta/lookup/",
1943
- {
1944
- searchParams
1469
+ if (options.account_id) {
1470
+ searchParams.account_id = options.account_id;
1471
+ }
1472
+ if (options.owner) {
1473
+ searchParams.owner = options.owner;
1474
+ }
1475
+ searchParams.limit = options.pageSize.toString();
1476
+ if (options.cursor) {
1477
+ searchParams.offset = options.cursor;
1478
+ }
1479
+ console.log({ searchParams });
1480
+ const data = await api.get(
1481
+ "/api/v4/authentications/",
1482
+ {
1483
+ searchParams,
1484
+ customErrorHandler: ({ status }) => {
1485
+ if (status === 401) {
1486
+ return new ZapierAuthenticationError(
1487
+ `Authentication failed. Your token may not have permission to access authentications or may be expired. (HTTP ${status})`,
1488
+ { statusCode: status }
1489
+ );
1490
+ }
1491
+ if (status === 403) {
1492
+ return new ZapierAuthenticationError(
1493
+ `Access forbidden. Your token may not have the required scopes to list authentications. (HTTP ${status})`,
1494
+ { statusCode: status }
1495
+ );
1496
+ }
1497
+ return void 0;
1498
+ },
1499
+ authRequired: true
1500
+ }
1501
+ );
1502
+ let auths = (data.results || []).map(
1503
+ (auth) => normalizeAuthenticationItem(auth)
1504
+ );
1505
+ if (options.title) {
1506
+ auths = auths.filter((auth) => auth.title === options.title);
1945
1507
  }
1946
- );
1947
- return {
1948
- data: implementationsEnvelope.results.map(
1949
- normalizeImplementationMetaToAppItem
1950
- ),
1951
- nextCursor: extractCursor(implementationsEnvelope)
1952
- };
1953
- }, ListAppsSchema);
1508
+ return {
1509
+ data: auths,
1510
+ nextCursor: extractCursor(data)
1511
+ };
1512
+ },
1513
+ ListAuthenticationsSchema
1514
+ );
1954
1515
  return {
1955
- listApps,
1516
+ listAuthentications,
1956
1517
  context: {
1957
1518
  meta: {
1958
- listApps: {
1959
- categories: ["app"],
1960
- inputSchema: ListAppsSchema
1519
+ listAuthentications: {
1520
+ categories: ["authentication"],
1521
+ inputSchema: ListAuthenticationsSchema
1961
1522
  }
1962
1523
  }
1963
1524
  }
@@ -1997,156 +1558,173 @@ var getAppPlugin = ({ context }) => {
1997
1558
  }
1998
1559
  };
1999
1560
  };
2000
- var ActionItemSchema = withFormatter(
2001
- ActionSchema.omit({ type: true, name: true }).extend({
2002
- app_key: z.string(),
2003
- // Mapped from selected_api
2004
- action_type: ActionSchema.shape.type,
2005
- // Mapped from original 'type' field
2006
- title: z.string(),
2007
- // Mapped from original 'name' field
2008
- type: z.literal("action")
2009
- // Fixed type identifier
2010
- }),
2011
- {
2012
- format: (item) => {
2013
- const details = [];
2014
- details.push({
2015
- text: `Type: ${item.action_type}`,
2016
- style: "accent"
2017
- });
2018
- if (item.app_key) {
2019
- details.push({
2020
- text: `App: ${item.app_key}`,
2021
- style: "normal"
2022
- });
1561
+ var GetActionSchema = z.object({
1562
+ appKey: AppKeyPropertySchema,
1563
+ actionType: ActionTypePropertySchema,
1564
+ actionKey: ActionKeyPropertySchema
1565
+ }).describe("Get detailed information about a specific action");
1566
+
1567
+ // src/plugins/getAction/index.ts
1568
+ var getActionPlugin = ({ sdk }) => {
1569
+ const getAction = createFunction(async function getAction2(options) {
1570
+ const { actionKey, actionType, appKey } = options;
1571
+ const actionsResult = await sdk.listActions({ appKey });
1572
+ for (const action of actionsResult.data) {
1573
+ if (action.key === actionKey && action.action_type === actionType) {
1574
+ return { data: action };
2023
1575
  }
2024
- if (item.description) {
2025
- details.push({ text: item.description, style: "dim" });
1576
+ }
1577
+ throw new ZapierResourceNotFoundError(
1578
+ `Action not found: ${actionKey} with type ${actionType}`,
1579
+ { resourceType: "Action", resourceId: `${actionKey} (${actionType})` }
1580
+ );
1581
+ }, GetActionSchema);
1582
+ return {
1583
+ getAction,
1584
+ context: {
1585
+ meta: {
1586
+ getAction: {
1587
+ categories: ["action"],
1588
+ inputSchema: GetActionSchema
1589
+ }
2026
1590
  }
2027
- return {
2028
- title: item.title || item.name || item.key,
2029
- subtitle: `(${item.key})`,
2030
- details
2031
- };
2032
1591
  }
2033
- }
2034
- );
2035
-
2036
- // src/plugins/listActions/schemas.ts
2037
- var ListActionsSchema = withOutputSchema(
2038
- z.object({
2039
- appKey: AppKeyPropertySchema.describe(
2040
- "App key of actions to list (e.g., 'SlackCLIAPI')"
2041
- ),
2042
- actionType: ActionTypePropertySchema.optional().describe(
2043
- "Filter actions by type"
2044
- ),
2045
- pageSize: z.number().min(1).optional().describe("Number of actions per page"),
2046
- maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages")
2047
- }).describe("List all actions for a specific app"),
2048
- ActionItemSchema
2049
- );
1592
+ };
1593
+ };
1594
+ var GetAuthenticationSchema = z.object({
1595
+ authenticationId: z.number().int().positive().describe("Authentication ID to retrieve")
1596
+ }).describe("Get a specific authentication by ID");
2050
1597
 
2051
- // src/plugins/listActions/index.ts
2052
- var listActionsPlugin = ({ context }) => {
2053
- const listActions = createPaginatedFunction(async function listActionsPage(options) {
2054
- const { api, getVersionedImplementationId } = context;
2055
- const selectedApi = await getVersionedImplementationId(options.appKey);
2056
- if (!selectedApi) {
2057
- throw new ZapierConfigurationError(
2058
- "No current_implementation_id found for app",
2059
- { configType: "current_implementation_id" }
2060
- );
2061
- }
2062
- const searchParams = {
2063
- global: "true",
2064
- public_only: "true",
2065
- selected_apis: selectedApi
2066
- };
1598
+ // src/plugins/getAuthentication/index.ts
1599
+ var getAuthenticationPlugin = ({ context }) => {
1600
+ const getAuthentication = createFunction(async function getAuthentication2(options) {
1601
+ const { api } = context;
1602
+ const { authenticationId } = options;
2067
1603
  const data = await api.get(
2068
- "/api/v4/implementations/",
1604
+ `/api/v4/authentications/${authenticationId}/`,
2069
1605
  {
2070
- searchParams,
2071
1606
  customErrorHandler: ({ status }) => {
2072
1607
  if (status === 401) {
2073
1608
  return new ZapierAuthenticationError(
2074
- `Authentication failed. Your token may not have permission to access implementations or may be expired. (HTTP ${status})`,
1609
+ `Authentication failed. Your token may not have permission to access authentications or may be expired. (HTTP ${status})`,
2075
1610
  { statusCode: status }
2076
1611
  );
2077
1612
  }
2078
1613
  if (status === 403) {
2079
1614
  return new ZapierAuthenticationError(
2080
- `Access forbidden. Your token may not have the required scopes to list implementations. (HTTP ${status})`,
1615
+ `Access forbidden. Your token may not have the required scopes to get authentication ${authenticationId}. (HTTP ${status})`,
2081
1616
  { statusCode: status }
2082
1617
  );
2083
1618
  }
1619
+ if (status === 404) {
1620
+ return new ZapierResourceNotFoundError(
1621
+ `Authentication ${authenticationId} not found. It may not exist or you may not have access to it. (HTTP ${status})`,
1622
+ {
1623
+ resourceType: "Authentication",
1624
+ resourceId: String(authenticationId)
1625
+ }
1626
+ );
1627
+ }
2084
1628
  return void 0;
2085
- }
1629
+ },
1630
+ authRequired: true
2086
1631
  }
2087
1632
  );
2088
- let allActions = [];
2089
- for (const implementation of data.results || []) {
2090
- if (implementation.actions) {
2091
- for (const action of implementation.actions) {
2092
- const actionWithContext = {
2093
- ...action,
2094
- selected_api: action.selected_api || implementation.selected_api
2095
- };
2096
- allActions.push(normalizeActionItem(actionWithContext));
1633
+ return {
1634
+ data: normalizeAuthenticationItem(data)
1635
+ };
1636
+ }, GetAuthenticationSchema);
1637
+ return {
1638
+ getAuthentication,
1639
+ context: {
1640
+ meta: {
1641
+ getAuthentication: {
1642
+ categories: ["authentication"],
1643
+ inputSchema: GetAuthenticationSchema
2097
1644
  }
2098
1645
  }
2099
1646
  }
2100
- if (options.actionType) {
2101
- allActions = allActions.filter(
2102
- (action) => action.action_type === options.actionType
2103
- );
2104
- }
2105
- return {
2106
- data: allActions,
2107
- nextCursor: void 0
2108
- };
2109
- }, ListActionsSchema);
1647
+ };
1648
+ };
1649
+ var FindFirstAuthenticationSchema = z.object({
1650
+ appKey: AppKeyPropertySchema.optional().describe(
1651
+ "App key of authentication to find (e.g., 'SlackCLIAPI')"
1652
+ ),
1653
+ search: z.string().optional().describe("Search term to filter authentications by title"),
1654
+ title: z.string().optional().describe("Filter authentications by exact title match"),
1655
+ account_id: z.string().optional().describe("Filter by account ID"),
1656
+ owner: z.string().optional().describe("Filter by owner")
1657
+ }).describe("Find the first authentication matching the criteria");
1658
+
1659
+ // src/plugins/findFirstAuthentication/index.ts
1660
+ var findFirstAuthenticationPlugin = ({ sdk }) => {
1661
+ const findFirstAuthentication = createFunction(
1662
+ async function findFirstAuthentication2(options = {}) {
1663
+ const authsResponse = await sdk.listAuthentications({
1664
+ ...options,
1665
+ maxItems: 1
1666
+ });
1667
+ return {
1668
+ data: authsResponse.data.length > 0 ? authsResponse.data[0] : null
1669
+ };
1670
+ },
1671
+ FindFirstAuthenticationSchema
1672
+ );
2110
1673
  return {
2111
- listActions,
1674
+ findFirstAuthentication,
2112
1675
  context: {
2113
1676
  meta: {
2114
- listActions: {
2115
- categories: ["action"],
2116
- inputSchema: ListActionsSchema
1677
+ findFirstAuthentication: {
1678
+ categories: ["authentication"],
1679
+ inputSchema: FindFirstAuthenticationSchema
2117
1680
  }
2118
1681
  }
2119
- }
2120
- };
2121
- };
2122
- var GetActionSchema = z.object({
2123
- appKey: AppKeyPropertySchema,
2124
- actionType: ActionTypePropertySchema,
2125
- actionKey: ActionKeyPropertySchema
2126
- }).describe("Get detailed information about a specific action");
2127
-
2128
- // src/plugins/getAction/index.ts
2129
- var getActionPlugin = ({ sdk }) => {
2130
- const getAction = createFunction(async function getAction2(options) {
2131
- const { actionKey, actionType, appKey } = options;
2132
- const actionsResult = await sdk.listActions({ appKey });
2133
- for (const action of actionsResult.data) {
2134
- if (action.key === actionKey && action.action_type === actionType) {
2135
- return { data: action };
1682
+ }
1683
+ };
1684
+ };
1685
+ var FindUniqueAuthenticationSchema = z.object({
1686
+ appKey: AppKeyPropertySchema.optional().describe(
1687
+ "App key of authentication to find (e.g., 'SlackCLIAPI')"
1688
+ ),
1689
+ search: z.string().optional().describe("Search term to filter authentications by title"),
1690
+ title: z.string().optional().describe("Filter authentications by exact title match"),
1691
+ account_id: z.string().optional().describe("Filter by account ID"),
1692
+ owner: z.string().optional().describe("Filter by owner")
1693
+ }).describe("Find a unique authentication matching the criteria");
1694
+
1695
+ // src/plugins/findUniqueAuthentication/index.ts
1696
+ var findUniqueAuthenticationPlugin = ({ sdk }) => {
1697
+ const findUniqueAuthentication = createFunction(
1698
+ async function findUniqueAuthentication2(options = {}) {
1699
+ const authsResponse = await sdk.listAuthentications({
1700
+ ...options,
1701
+ maxItems: 2
1702
+ // Get up to 2 to check for uniqueness
1703
+ });
1704
+ if (authsResponse.data.length === 0) {
1705
+ throw new ZapierResourceNotFoundError(
1706
+ "No authentication found matching the specified criteria",
1707
+ { resourceType: "Authentication" }
1708
+ );
1709
+ }
1710
+ if (authsResponse.data.length > 1) {
1711
+ throw new ZapierValidationError(
1712
+ "Multiple authentications found matching the specified criteria. Expected exactly one."
1713
+ );
2136
1714
  }
2137
- }
2138
- throw new ZapierResourceNotFoundError(
2139
- `Action not found: ${actionKey} with type ${actionType}`,
2140
- { resourceType: "Action", resourceId: `${actionKey} (${actionType})` }
2141
- );
2142
- }, GetActionSchema);
1715
+ return {
1716
+ data: authsResponse.data[0]
1717
+ };
1718
+ },
1719
+ FindUniqueAuthenticationSchema
1720
+ );
2143
1721
  return {
2144
- getAction,
1722
+ findUniqueAuthentication,
2145
1723
  context: {
2146
1724
  meta: {
2147
- getAction: {
2148
- categories: ["action"],
2149
- inputSchema: GetActionSchema
1725
+ findUniqueAuthentication: {
1726
+ categories: ["authentication"],
1727
+ inputSchema: FindUniqueAuthenticationSchema
2150
1728
  }
2151
1729
  }
2152
1730
  }
@@ -2257,612 +1835,1040 @@ var runActionPlugin = ({ sdk, context }) => {
2257
1835
  inputSchema: RunActionSchema
2258
1836
  }
2259
1837
  }
2260
- }
2261
- };
2262
- };
2263
- var ListAuthenticationsSchema = z.object({
2264
- appKey: AppKeyPropertySchema.optional().describe(
2265
- "App key of authentications to list (e.g., 'SlackCLIAPI')"
2266
- ),
2267
- search: z.string().optional().describe("Search term to filter authentications by title"),
2268
- title: z.string().optional().describe("Filter authentications by exact title match"),
2269
- account_id: z.string().optional().describe("Filter by account ID"),
2270
- owner: z.string().optional().describe("Filter by owner"),
2271
- pageSize: z.number().min(1).optional().describe("Number of authentications per page"),
2272
- maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages")
2273
- }).describe("List available authentications with optional filtering");
2274
-
2275
- // src/plugins/listAuthentications/index.ts
2276
- var listAuthenticationsPlugin = ({ context }) => {
2277
- const listAuthentications = createPaginatedFunction(
2278
- async function listAuthenticationsPage(options) {
2279
- const { api, getVersionedImplementationId } = context;
2280
- const searchParams = {};
2281
- if (options.appKey) {
2282
- const implementationId = await getVersionedImplementationId(
2283
- options.appKey
1838
+ }
1839
+ };
1840
+ };
1841
+ var RelayRequestSchema = z.object({
1842
+ url: z.string().url().describe("The URL to request (will be proxied through Relay)"),
1843
+ method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]).optional().describe("HTTP method"),
1844
+ body: z.any().optional().describe("Request body as a string"),
1845
+ authenticationId: z.number().int().optional().describe("Zapier authentication ID to use for the request"),
1846
+ callbackUrl: z.string().url().optional().describe("URL to send async response to (makes request async)"),
1847
+ authenticationTemplate: z.string().optional().describe(
1848
+ "Optional JSON string authentication template to bypass Notary lookup"
1849
+ ),
1850
+ headers: z.union([
1851
+ z.record(z.string()),
1852
+ z.instanceof(Headers),
1853
+ z.array(z.tuple([z.string(), z.string()]))
1854
+ ]).optional().describe("Request headers")
1855
+ }).extend({
1856
+ relayBaseUrl: z.string().optional().describe("Base URL for Relay service")
1857
+ }).describe("Make authenticated HTTP requests through Zapier's Relay service");
1858
+ var RelayFetchSchema = RelayRequestSchema;
1859
+
1860
+ // src/plugins/request/index.ts
1861
+ function transformUrlToRelayPath(url) {
1862
+ const targetUrl = new URL(url);
1863
+ const relayPath = `/relay/${targetUrl.host}${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
1864
+ return relayPath;
1865
+ }
1866
+ var requestPlugin = ({ context }) => {
1867
+ const request = createFunction(async function request2(options) {
1868
+ const { api } = context;
1869
+ const {
1870
+ url,
1871
+ method = "GET",
1872
+ body,
1873
+ headers: optionsHeaders,
1874
+ authenticationId,
1875
+ callbackUrl,
1876
+ authenticationTemplate
1877
+ } = options;
1878
+ const relayPath = transformUrlToRelayPath(url);
1879
+ const headers = {};
1880
+ if (optionsHeaders) {
1881
+ const headerEntries = optionsHeaders instanceof Headers ? Array.from(optionsHeaders.entries()) : Array.isArray(optionsHeaders) ? optionsHeaders : Object.entries(optionsHeaders);
1882
+ for (const [key, value] of headerEntries) {
1883
+ headers[key] = value;
1884
+ }
1885
+ }
1886
+ if (authenticationId) {
1887
+ headers["X-Relay-Authentication-Id"] = authenticationId.toString();
1888
+ }
1889
+ if (callbackUrl) {
1890
+ headers["X-Relay-Callback-Url"] = callbackUrl;
1891
+ }
1892
+ if (authenticationTemplate) {
1893
+ headers["X-Authentication-Template"] = authenticationTemplate;
1894
+ }
1895
+ return await api.fetch(relayPath, {
1896
+ method,
1897
+ body,
1898
+ headers
1899
+ });
1900
+ }, RelayRequestSchema);
1901
+ return {
1902
+ request,
1903
+ context: {
1904
+ meta: {
1905
+ request: {
1906
+ categories: ["http"],
1907
+ inputSchema: RelayRequestSchema
1908
+ }
1909
+ }
1910
+ }
1911
+ };
1912
+ };
1913
+ var ManifestSchema = z.object({
1914
+ apps: z.record(
1915
+ z.string(),
1916
+ z.object({
1917
+ implementationName: z.string().describe(
1918
+ "Base implementation name without version (e.g., 'SlackCLIAPI')"
1919
+ ),
1920
+ version: z.string().describe("Version string (e.g., '1.21.1')")
1921
+ })
1922
+ )
1923
+ }).describe("Manifest mapping app keys to version information");
1924
+ z.object({
1925
+ manifestPath: z.string().optional().describe("Path to manifest file"),
1926
+ manifest: z.record(
1927
+ z.string(),
1928
+ z.object({
1929
+ implementationName: z.string(),
1930
+ version: z.string().optional()
1931
+ })
1932
+ ).optional().describe("Direct manifest object")
1933
+ });
1934
+
1935
+ // src/plugins/manifest/index.ts
1936
+ function parseManifestContent(content, source) {
1937
+ try {
1938
+ const parsed = JSON.parse(content);
1939
+ if (parsed?.apps && typeof parsed?.apps === "object") {
1940
+ const result = ManifestSchema.safeParse(parsed);
1941
+ if (result.success) {
1942
+ return result.data;
1943
+ }
1944
+ console.warn(`\u26A0\uFE0F Invalid manifest format in ${source}: ${result.error}`);
1945
+ }
1946
+ return null;
1947
+ } catch (error) {
1948
+ console.warn(`\u26A0\uFE0F Failed to parse manifest from ${source}:`, error);
1949
+ return null;
1950
+ }
1951
+ }
1952
+ function loadManifestFromFile(filePath) {
1953
+ try {
1954
+ const resolvedPath = resolve(filePath);
1955
+ const content = readFileSync(resolvedPath, "utf8");
1956
+ return parseManifestContent(content, resolvedPath);
1957
+ } catch {
1958
+ console.warn(`\u26A0\uFE0F Failed to load manifest from ${filePath}`);
1959
+ return null;
1960
+ }
1961
+ }
1962
+ var emitWarning = (appKey) => {
1963
+ console.warn(
1964
+ `
1965
+ ${"\u26A0\uFE0F".padEnd(3)} ${"WARNING".padEnd(8)} No manifest version found for '${appKey}'`
1966
+ );
1967
+ console.warn(
1968
+ ` ${"\u21B3".padEnd(3)} Using a manifest ensures version locking and prevents unexpected behavior due to version changes.`
1969
+ );
1970
+ console.warn(
1971
+ ` ${"\u21B3".padEnd(3)} Generate/update the manifest with: \`zapier-sdk lock-version ${appKey}\`
1972
+ `
1973
+ );
1974
+ };
1975
+ var manifestPlugin = (params) => {
1976
+ const { sdk, context } = params;
1977
+ const { api, options } = context;
1978
+ const { manifestPath = ".zapierrc", manifest } = options || {};
1979
+ let resolvedManifest;
1980
+ function resolveManifest() {
1981
+ if (manifest) {
1982
+ return manifest;
1983
+ }
1984
+ if (manifestPath) {
1985
+ return loadManifestFromFile(manifestPath);
1986
+ }
1987
+ return null;
1988
+ }
1989
+ const getResolvedManifest = () => {
1990
+ if (typeof resolvedManifest === "undefined") {
1991
+ resolvedManifest = resolveManifest() ?? null;
1992
+ }
1993
+ return resolvedManifest;
1994
+ };
1995
+ const getManifestEntry = (appKey) => {
1996
+ return getResolvedManifest()?.apps?.[appKey] || null;
1997
+ };
1998
+ const getImplementation = async (appKey) => {
1999
+ let selectedApi = null;
2000
+ const manifestImplementation = getResolvedManifest()?.apps?.[appKey];
2001
+ const [versionlessAppKey, version] = splitVersionedKey(appKey);
2002
+ if (version) {
2003
+ selectedApi = `${versionlessAppKey}@${version}`;
2004
+ } else if (manifestImplementation) {
2005
+ selectedApi = `${manifestImplementation.implementationName}@${manifestImplementation.version || "latest"}`;
2006
+ }
2007
+ if (selectedApi) {
2008
+ const searchParams = {
2009
+ selected_apis: selectedApi
2010
+ };
2011
+ const implementationData = await api.get(
2012
+ "/api/v4/implementations/",
2013
+ {
2014
+ searchParams
2015
+ }
2016
+ );
2017
+ const implementationResults = implementationData.results[0];
2018
+ if (!implementationResults) return null;
2019
+ return normalizeImplementationToAppItem(implementationResults);
2020
+ }
2021
+ emitWarning(appKey);
2022
+ const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2023
+ const apps = [];
2024
+ for await (const app2 of appsIterator) {
2025
+ apps.push(app2);
2026
+ break;
2027
+ }
2028
+ if (apps.length === 0) {
2029
+ return null;
2030
+ }
2031
+ const app = apps[0];
2032
+ return app;
2033
+ };
2034
+ const getVersionedImplementationId = async (appKey) => {
2035
+ const manifestEntry = getManifestEntry(appKey);
2036
+ if (manifestEntry) {
2037
+ return `${manifestEntry.implementationName}@${manifestEntry.version || "latest"}`;
2038
+ }
2039
+ const implementation = await getImplementation(appKey);
2040
+ if (!implementation) return null;
2041
+ return implementation.current_implementation_id;
2042
+ };
2043
+ return {
2044
+ context: {
2045
+ getVersionedImplementationId,
2046
+ getManifestEntry,
2047
+ getImplementation
2048
+ }
2049
+ };
2050
+ };
2051
+ var LockVersionSchema = z.object({
2052
+ appKey: z.string().describe("The app key to lock version for (e.g., 'slack', 'gmail')")
2053
+ });
2054
+ var lockVersionPlugin = ({ sdk }) => {
2055
+ const lockVersion = createFunction(
2056
+ async function lockVersion2(options) {
2057
+ const { appKey, configPath = ".zapierrc" } = options;
2058
+ const resolvedPath = resolve(configPath);
2059
+ const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2060
+ const apps = [];
2061
+ for await (const app2 of appsIterator) {
2062
+ apps.push(app2);
2063
+ break;
2064
+ }
2065
+ const app = apps[0];
2066
+ const currentImplementationId = app.current_implementation_id;
2067
+ const [implementationName, version] = currentImplementationId.split("@");
2068
+ if (!implementationName || !version) {
2069
+ throw new Error(
2070
+ `Invalid implementation ID format: ${currentImplementationId}. Expected format: <implementationName>@<version>`
2284
2071
  );
2285
- if (implementationId) {
2286
- const [versionlessSelectedApi] = splitVersionedKey(implementationId);
2287
- searchParams.versionless_selected_api = versionlessSelectedApi;
2288
- }
2289
- }
2290
- if (options.search) {
2291
- searchParams.search = options.search;
2292
- } else if (options.title) {
2293
- searchParams.search = options.title;
2294
- }
2295
- if (options.account_id) {
2296
- searchParams.account_id = options.account_id;
2297
2072
  }
2298
- if (options.owner) {
2299
- searchParams.owner = options.owner;
2300
- }
2301
- searchParams.limit = options.pageSize.toString();
2302
- if (options.cursor) {
2303
- searchParams.offset = options.cursor;
2304
- }
2305
- console.log({ searchParams });
2306
- const data = await api.get(
2307
- "/api/v4/authentications/",
2308
- {
2309
- searchParams,
2310
- customErrorHandler: ({ status }) => {
2311
- if (status === 401) {
2312
- return new ZapierAuthenticationError(
2313
- `Authentication failed. Your token may not have permission to access authentications or may be expired. (HTTP ${status})`,
2314
- { statusCode: status }
2315
- );
2316
- }
2317
- if (status === 403) {
2318
- return new ZapierAuthenticationError(
2319
- `Access forbidden. Your token may not have the required scopes to list authentications. (HTTP ${status})`,
2320
- { statusCode: status }
2321
- );
2322
- }
2323
- return void 0;
2324
- },
2325
- authRequired: true
2073
+ let config = { apps: {} };
2074
+ if (existsSync(resolvedPath)) {
2075
+ try {
2076
+ const configContent = readFileSync(resolvedPath, "utf8");
2077
+ config = JSON.parse(configContent);
2078
+ if (!config.apps) {
2079
+ config.apps = {};
2080
+ }
2081
+ } catch (error) {
2082
+ console.warn(
2083
+ `\u26A0\uFE0F Failed to parse existing config file, creating new one: ${error}`
2084
+ );
2085
+ config = { apps: {} };
2326
2086
  }
2327
- );
2328
- let auths = (data.results || []).map(
2329
- (auth) => normalizeAuthenticationItem(auth)
2330
- );
2331
- if (options.title) {
2332
- auths = auths.filter((auth) => auth.title === options.title);
2333
2087
  }
2088
+ config.apps[appKey] = {
2089
+ implementationName,
2090
+ version
2091
+ };
2092
+ writeFileSync(resolvedPath, JSON.stringify(config, null, 2));
2334
2093
  return {
2335
- data: auths,
2336
- nextCursor: extractCursor(data)
2094
+ data: {
2095
+ ...app,
2096
+ implementationName,
2097
+ version
2098
+ },
2099
+ configPath: resolvedPath
2337
2100
  };
2338
2101
  },
2339
- ListAuthenticationsSchema
2102
+ LockVersionSchema.extend({
2103
+ configPath: z.string().optional().describe("Path to .zapierrc file (defaults to '.zapierrc')")
2104
+ })
2340
2105
  );
2341
2106
  return {
2342
- listAuthentications,
2107
+ lockVersion,
2343
2108
  context: {
2344
2109
  meta: {
2345
- listAuthentications: {
2346
- categories: ["authentication"],
2347
- inputSchema: ListAuthenticationsSchema
2110
+ lockVersion: {
2111
+ categories: ["utility"],
2112
+ inputSchema: LockVersionSchema
2348
2113
  }
2349
2114
  }
2350
2115
  }
2351
2116
  };
2352
2117
  };
2353
- var GetAuthenticationSchema = z.object({
2354
- authenticationId: z.number().int().positive().describe("Authentication ID to retrieve")
2355
- }).describe("Get a specific authentication by ID");
2356
-
2357
- // src/plugins/getAuthentication/index.ts
2358
- var getAuthenticationPlugin = ({ context }) => {
2359
- const getAuthentication = createFunction(async function getAuthentication2(options) {
2360
- const { api } = context;
2361
- const { authenticationId } = options;
2362
- const data = await api.get(
2363
- `/api/v4/authentications/${authenticationId}/`,
2364
- {
2365
- customErrorHandler: ({ status }) => {
2366
- if (status === 401) {
2367
- return new ZapierAuthenticationError(
2368
- `Authentication failed. Your token may not have permission to access authentications or may be expired. (HTTP ${status})`,
2369
- { statusCode: status }
2370
- );
2371
- }
2372
- if (status === 403) {
2373
- return new ZapierAuthenticationError(
2374
- `Access forbidden. Your token may not have the required scopes to get authentication ${authenticationId}. (HTTP ${status})`,
2375
- { statusCode: status }
2376
- );
2377
- }
2378
- if (status === 404) {
2379
- return new ZapierResourceNotFoundError(
2380
- `Authentication ${authenticationId} not found. It may not exist or you may not have access to it. (HTTP ${status})`,
2381
- {
2382
- resourceType: "Authentication",
2383
- resourceId: String(authenticationId)
2384
- }
2385
- );
2386
- }
2387
- return void 0;
2388
- },
2389
- authRequired: true
2118
+ var UserProfileItemSchema = withFormatter(
2119
+ UserProfileSchema.omit({ user_id: true }).extend({
2120
+ full_name: z.string()
2121
+ // Computed field: first_name + " " + last_name
2122
+ }),
2123
+ {
2124
+ format: (item) => {
2125
+ const details = [];
2126
+ details.push({ text: item.email, style: "dim" });
2127
+ if (item.timezone) {
2128
+ details.push({
2129
+ text: `Timezone: ${item.timezone}`,
2130
+ style: "accent"
2131
+ });
2390
2132
  }
2391
- );
2133
+ details.push({
2134
+ text: `Member since: ${item.since_signup}`,
2135
+ style: "dim"
2136
+ });
2137
+ return {
2138
+ title: item.full_name,
2139
+ subtitle: `@${item.username}`,
2140
+ details
2141
+ };
2142
+ }
2143
+ }
2144
+ );
2145
+
2146
+ // src/plugins/getProfile/schemas.ts
2147
+ var GetProfileSchema = withOutputSchema(
2148
+ z.object({}).optional().describe("Get current user's profile information"),
2149
+ UserProfileItemSchema
2150
+ );
2151
+
2152
+ // src/plugins/getProfile/index.ts
2153
+ var getProfilePlugin = ({ context }) => {
2154
+ const getProfile = createFunction(async function getProfile2() {
2155
+ const profile = await context.api.get("/api/v4/profile/", {
2156
+ authRequired: true
2157
+ });
2158
+ const { user_id: _unusedUserId, ...data } = profile;
2392
2159
  return {
2393
- data: normalizeAuthenticationItem(data)
2160
+ data: {
2161
+ ...data,
2162
+ // Pass through all API response fields
2163
+ full_name: `${profile.first_name} ${profile.last_name}`
2164
+ // Computed field
2165
+ }
2394
2166
  };
2395
- }, GetAuthenticationSchema);
2167
+ }, GetProfileSchema);
2396
2168
  return {
2397
- getAuthentication,
2169
+ getProfile,
2398
2170
  context: {
2399
2171
  meta: {
2400
- getAuthentication: {
2401
- categories: ["authentication"],
2402
- inputSchema: GetAuthenticationSchema
2172
+ getProfile: {
2173
+ categories: ["account"],
2174
+ inputSchema: GetProfileSchema
2175
+ }
2176
+ }
2177
+ }
2178
+ };
2179
+ };
2180
+
2181
+ // src/api/auth.ts
2182
+ function isJwt(token) {
2183
+ const parts = token.split(".");
2184
+ if (parts.length !== 3) {
2185
+ return false;
2186
+ }
2187
+ const base64UrlPattern = /^[A-Za-z0-9_-]+$/;
2188
+ return parts.every((part) => part.length > 0 && base64UrlPattern.test(part));
2189
+ }
2190
+ function getAuthorizationHeader(token) {
2191
+ if (isJwt(token)) {
2192
+ return `JWT ${token}`;
2193
+ }
2194
+ return `Bearer ${token}`;
2195
+ }
2196
+
2197
+ // src/api/debug.ts
2198
+ function createDebugLogger(enabled) {
2199
+ if (!enabled) {
2200
+ return () => {
2201
+ };
2202
+ }
2203
+ return (message, data) => {
2204
+ console.log(`[Zapier SDK] ${message}`, data || "");
2205
+ };
2206
+ }
2207
+ function createDebugFetch(options) {
2208
+ const { originalFetch, debugLog } = options;
2209
+ return async (input, options2) => {
2210
+ const startTime = Date.now();
2211
+ const url = typeof input === "string" ? input : input.toString();
2212
+ const method = options2?.method || "GET";
2213
+ debugLog(`\u2192 ${method} ${url}`, {
2214
+ headers: options2?.headers,
2215
+ body: options2?.body && typeof options2.body === "string" ? (() => {
2216
+ try {
2217
+ return JSON.parse(options2.body);
2218
+ } catch {
2219
+ return options2.body;
2403
2220
  }
2404
- }
2405
- }
2406
- };
2407
- };
2408
- var FindFirstAuthenticationSchema = z.object({
2409
- appKey: AppKeyPropertySchema.optional().describe(
2410
- "App key of authentication to find (e.g., 'SlackCLIAPI')"
2411
- ),
2412
- search: z.string().optional().describe("Search term to filter authentications by title"),
2413
- title: z.string().optional().describe("Filter authentications by exact title match"),
2414
- account_id: z.string().optional().describe("Filter by account ID"),
2415
- owner: z.string().optional().describe("Filter by owner")
2416
- }).describe("Find the first authentication matching the criteria");
2417
-
2418
- // src/plugins/findFirstAuthentication/index.ts
2419
- var findFirstAuthenticationPlugin = ({ sdk }) => {
2420
- const findFirstAuthentication = createFunction(
2421
- async function findFirstAuthentication2(options = {}) {
2422
- const authsResponse = await sdk.listAuthentications({
2423
- ...options,
2424
- maxItems: 1
2221
+ })() : options2?.body
2222
+ });
2223
+ try {
2224
+ const response = await originalFetch(input, options2);
2225
+ const duration = Date.now() - startTime;
2226
+ debugLog(`\u2190 ${response.status} ${response.statusText} (${duration}ms)`, {
2227
+ url,
2228
+ method,
2229
+ status: response.status
2425
2230
  });
2426
- return {
2427
- data: authsResponse.data.length > 0 ? authsResponse.data[0] : null
2428
- };
2429
- },
2430
- FindFirstAuthenticationSchema
2431
- );
2432
- return {
2433
- findFirstAuthentication,
2434
- context: {
2435
- meta: {
2436
- findFirstAuthentication: {
2437
- categories: ["authentication"],
2438
- inputSchema: FindFirstAuthenticationSchema
2439
- }
2440
- }
2231
+ return response;
2232
+ } catch (error) {
2233
+ const duration = Date.now() - startTime;
2234
+ debugLog(`\u2716 Request failed (${duration}ms)`, {
2235
+ url,
2236
+ method,
2237
+ error: error instanceof Error ? error.message : error
2238
+ });
2239
+ throw error;
2441
2240
  }
2442
2241
  };
2443
- };
2444
- var FindUniqueAuthenticationSchema = z.object({
2445
- appKey: AppKeyPropertySchema.optional().describe(
2446
- "App key of authentication to find (e.g., 'SlackCLIAPI')"
2447
- ),
2448
- search: z.string().optional().describe("Search term to filter authentications by title"),
2449
- title: z.string().optional().describe("Filter authentications by exact title match"),
2450
- account_id: z.string().optional().describe("Filter by account ID"),
2451
- owner: z.string().optional().describe("Filter by owner")
2452
- }).describe("Find a unique authentication matching the criteria");
2242
+ }
2453
2243
 
2454
- // src/plugins/findUniqueAuthentication/index.ts
2455
- var findUniqueAuthenticationPlugin = ({ sdk }) => {
2456
- const findUniqueAuthentication = createFunction(
2457
- async function findUniqueAuthentication2(options = {}) {
2458
- const authsResponse = await sdk.listAuthentications({
2459
- ...options,
2460
- maxItems: 2
2461
- // Get up to 2 to check for uniqueness
2462
- });
2463
- if (authsResponse.data.length === 0) {
2464
- throw new ZapierResourceNotFoundError(
2465
- "No authentication found matching the specified criteria",
2466
- { resourceType: "Authentication" }
2467
- );
2244
+ // src/api/polling.ts
2245
+ async function pollUntilComplete(options) {
2246
+ const {
2247
+ fetchPoll,
2248
+ maxAttempts = 30,
2249
+ initialDelay = 50,
2250
+ maxDelay = 1e3,
2251
+ successStatus = 200,
2252
+ pendingStatus = 202,
2253
+ resultExtractor = (response) => response
2254
+ } = options;
2255
+ let delay = initialDelay;
2256
+ let errorCount = 0;
2257
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
2258
+ const response = await fetchPoll();
2259
+ if (response.status === successStatus) {
2260
+ errorCount = 0;
2261
+ const result = await response.json();
2262
+ return resultExtractor(result);
2263
+ } else if (response.status === pendingStatus) {
2264
+ errorCount = 0;
2265
+ if (attempt < maxAttempts - 1) {
2266
+ await new Promise((resolve3) => setTimeout(resolve3, delay));
2267
+ delay = Math.min(delay * 2, maxDelay);
2268
+ continue;
2468
2269
  }
2469
- if (authsResponse.data.length > 1) {
2470
- throw new ZapierValidationError(
2471
- "Multiple authentications found matching the specified criteria. Expected exactly one."
2270
+ } else {
2271
+ errorCount++;
2272
+ if (errorCount >= 3) {
2273
+ throw new ZapierApiError(
2274
+ `Poll request failed: ${response.status} ${response.statusText}`,
2275
+ { statusCode: response.status }
2472
2276
  );
2473
2277
  }
2474
- return {
2475
- data: authsResponse.data[0]
2476
- };
2477
- },
2478
- FindUniqueAuthenticationSchema
2278
+ if (attempt < maxAttempts - 1) {
2279
+ await new Promise((resolve3) => setTimeout(resolve3, delay));
2280
+ delay = Math.min(delay * 2, maxDelay);
2281
+ continue;
2282
+ }
2283
+ }
2284
+ }
2285
+ throw new ZapierTimeoutError(
2286
+ `Operation timed out after ${maxAttempts} attempts`,
2287
+ { attempts: maxAttempts, maxAttempts }
2479
2288
  );
2480
- return {
2481
- findUniqueAuthentication,
2482
- context: {
2483
- meta: {
2484
- findUniqueAuthentication: {
2485
- categories: ["authentication"],
2486
- inputSchema: FindUniqueAuthenticationSchema
2289
+ }
2290
+
2291
+ // src/auth.ts
2292
+ function getTokenFromEnv() {
2293
+ return process.env.ZAPIER_TOKEN;
2294
+ }
2295
+ async function getTokenFromCliLogin(options = {}) {
2296
+ try {
2297
+ const { getToken } = await import('@zapier/zapier-sdk-cli-login');
2298
+ return await getToken(options);
2299
+ } catch {
2300
+ return void 0;
2301
+ }
2302
+ }
2303
+ async function getTokenFromEnvOrConfig(options = {}) {
2304
+ const envToken = getTokenFromEnv();
2305
+ if (envToken) {
2306
+ return envToken;
2307
+ }
2308
+ return getTokenFromCliLogin(options);
2309
+ }
2310
+
2311
+ // src/api/client.ts
2312
+ var SubdomainConfigMap = {
2313
+ // e.g. https://relay.zapier.com
2314
+ relay: {
2315
+ authHeader: "X-Relay-Authorization"
2316
+ }
2317
+ };
2318
+ var ZapierApiClient = class {
2319
+ constructor(options) {
2320
+ this.options = options;
2321
+ this.fetch = async (path, init) => {
2322
+ return this.plainFetch(path, init);
2323
+ };
2324
+ this.get = async (path, options = {}) => {
2325
+ return this.fetchJson("GET", path, void 0, options);
2326
+ };
2327
+ this.post = async (path, data, options = {}) => {
2328
+ return this.fetchJson("POST", path, data, options);
2329
+ };
2330
+ this.put = async (path, data, options = {}) => {
2331
+ return this.fetchJson("PUT", path, data, options);
2332
+ };
2333
+ this.delete = async (path, options = {}) => {
2334
+ return this.fetchJson("DELETE", path, void 0, options);
2335
+ };
2336
+ this.poll = async (path, options = {}) => {
2337
+ return pollUntilComplete({
2338
+ fetchPoll: () => this.plainFetch(path, {
2339
+ method: "GET",
2340
+ searchParams: options.searchParams,
2341
+ authRequired: options.authRequired
2342
+ }),
2343
+ maxAttempts: options.maxAttempts,
2344
+ initialDelay: options.initialDelay,
2345
+ maxDelay: options.maxDelay,
2346
+ successStatus: options.successStatus,
2347
+ pendingStatus: options.pendingStatus,
2348
+ resultExtractor: options.resultExtractor
2349
+ });
2350
+ };
2351
+ }
2352
+ // Helper to parse response data
2353
+ async parseResult(response) {
2354
+ try {
2355
+ return { type: "json", data: await response.json() };
2356
+ } catch {
2357
+ return { type: "text", data: await response.text() };
2358
+ }
2359
+ }
2360
+ // Helper to get a token from the different places it could be gotten
2361
+ async getAuthToken() {
2362
+ if (this.options.token) {
2363
+ return this.options.token;
2364
+ }
2365
+ if (this.options.getToken) {
2366
+ const token = await this.options.getToken();
2367
+ if (token) {
2368
+ return token;
2369
+ }
2370
+ }
2371
+ return getTokenFromEnvOrConfig({
2372
+ onEvent: this.options.onEvent,
2373
+ fetch: this.options.fetch
2374
+ });
2375
+ }
2376
+ // Helper to handle responses
2377
+ async handleResponse(params) {
2378
+ const { response, customErrorHandler, wasMissingAuthToken } = params;
2379
+ const { data: responseData } = await this.parseResult(response);
2380
+ if (response.ok) {
2381
+ return responseData;
2382
+ }
2383
+ const errorInfo = {
2384
+ status: response.status,
2385
+ statusText: response.statusText,
2386
+ data: responseData
2387
+ };
2388
+ if (customErrorHandler) {
2389
+ const customError = customErrorHandler(errorInfo);
2390
+ if (customError) {
2391
+ if (customError instanceof Error) {
2392
+ throw customError;
2393
+ } else {
2394
+ throw new Error(
2395
+ `customErrorHandler returned a non-Error: ${JSON.stringify(customError)}`
2396
+ );
2487
2397
  }
2488
2398
  }
2489
2399
  }
2490
- };
2491
- };
2492
- var ListInputFieldsSchema = z.object({
2493
- appKey: AppKeyPropertySchema,
2494
- actionType: ActionTypePropertySchema,
2495
- actionKey: ActionKeyPropertySchema,
2496
- authenticationId: AuthenticationIdPropertySchema.nullable().optional(),
2497
- inputs: InputsPropertySchema.optional().describe(
2498
- "Current input values that may affect available fields"
2499
- ),
2500
- pageSize: z.number().min(1).optional().describe("Number of input fields per page"),
2501
- maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages")
2502
- }).describe("Get the input fields required for a specific action");
2503
-
2504
- // src/plugins/listInputFields/index.ts
2505
- function getInputFieldTypeFromNeed(need) {
2506
- if (need.list) {
2507
- return "ARRAY" /* ARRAY */;
2400
+ const { message, errors } = this.parseErrorResponse(errorInfo);
2401
+ const errorOptions = {
2402
+ statusCode: response.status,
2403
+ errors
2404
+ };
2405
+ if (response.status === 404) {
2406
+ throw new ZapierNotFoundError(message, errorOptions);
2407
+ }
2408
+ if (response.status === 401 || response.status === 403) {
2409
+ if (wasMissingAuthToken) {
2410
+ throw new ZapierAuthenticationError(
2411
+ `Authentication required (HTTP ${response.status}). Please provide a token in options or set ZAPIER_TOKEN environment variable.`,
2412
+ errorOptions
2413
+ );
2414
+ }
2415
+ throw new ZapierAuthenticationError(message, errorOptions);
2416
+ }
2417
+ if (response.status === 400) {
2418
+ throw new ZapierValidationError(message, errorOptions);
2419
+ }
2420
+ throw new ZapierApiError(message, errorOptions);
2508
2421
  }
2509
- const typeMap = {
2510
- string: "STRING" /* STRING */,
2511
- decimal: "NUMBER" /* NUMBER */,
2512
- integer: "INTEGER" /* INTEGER */,
2513
- boolean: "BOOLEAN" /* BOOLEAN */,
2514
- dict: "OBJECT" /* OBJECT */
2515
- };
2516
- return typeMap[need.type || ""] || "STRING" /* STRING */;
2517
- }
2518
- function getInputFieldFormatFromNeed(need) {
2519
- if (need.prefill || need.choices) {
2520
- return "SELECT" /* SELECT */;
2422
+ hasErrorArray(data) {
2423
+ return typeof data === "object" && data !== null && "errors" in data && Array.isArray(data.errors);
2521
2424
  }
2522
- const formatMap = {
2523
- text: "MULTILINE" /* MULTILINE */,
2524
- datetime: "DATETIME" /* DATETIME */,
2525
- file: "FILE" /* FILE */,
2526
- password: "PASSWORD" /* PASSWORD */,
2527
- code: "CODE" /* CODE */
2528
- };
2529
- return formatMap[need.type || ""];
2530
- }
2531
- function getItemsTypeFromNeed(need) {
2532
- if (!need.list) {
2533
- return void 0;
2425
+ // Helper to check if data has API errors
2426
+ isApiErrorArray(dataArray) {
2427
+ const data = dataArray[0];
2428
+ return typeof data === "object" && data !== null && "message" in data && "code" in data && "title" in data && "detail" in data;
2534
2429
  }
2535
- const typeMap = {
2536
- string: "STRING" /* STRING */,
2537
- decimal: "NUMBER" /* NUMBER */,
2538
- integer: "INTEGER" /* INTEGER */,
2539
- boolean: "BOOLEAN" /* BOOLEAN */,
2540
- dict: "OBJECT" /* OBJECT */
2541
- };
2542
- return typeMap[need.type || ""] || "STRING" /* STRING */;
2543
- }
2544
- function transformNeedToInputFieldItem(need) {
2545
- const itemsType = getItemsTypeFromNeed(need);
2546
- return {
2547
- ...need,
2548
- // Pass through all original Need fields
2549
- id: need.key,
2550
- default_value: need.default || "",
2551
- depends_on: need.depends_on || [],
2552
- description: need.help_text || "",
2553
- invalidates_input_fields: need.alters_custom_fields || false,
2554
- is_required: need.required || false,
2555
- placeholder: need.placeholder || "",
2556
- title: need.label || "",
2557
- value_type: getInputFieldTypeFromNeed(need),
2558
- format: getInputFieldFormatFromNeed(need),
2559
- items: itemsType ? { type: itemsType } : void 0
2560
- };
2561
- }
2562
- var listInputFieldsPlugin = ({ context }) => {
2563
- const listInputFields = createPaginatedFunction(
2564
- async function listInputFieldsPage(options) {
2565
- const { api, getVersionedImplementationId } = context;
2566
- const { appKey, actionKey, actionType, authenticationId, inputs } = options;
2567
- const selectedApi = await getVersionedImplementationId(appKey);
2568
- if (!selectedApi) {
2569
- throw new ZapierConfigurationError(
2570
- "No current_implementation_id found for app",
2571
- { configType: "current_implementation_id" }
2572
- );
2573
- }
2574
- const needsRequest = {
2575
- selected_api: selectedApi,
2576
- action: actionKey,
2577
- type_of: actionType,
2578
- params: inputs || {}
2579
- };
2580
- if (authenticationId !== null) {
2581
- needsRequest.authentication_id = authenticationId;
2430
+ // Do our best to extract an error message from the response data
2431
+ extractErrorMessage(data) {
2432
+ if (typeof data === "string") {
2433
+ return data;
2434
+ }
2435
+ if (typeof data === "object" && data !== null) {
2436
+ if ("message" in data && typeof data.message === "string") {
2437
+ return data.message;
2582
2438
  }
2583
- const needsData = await api.post(
2584
- "/api/v4/implementations/needs/",
2585
- needsRequest
2586
- );
2587
- if (!needsData.success) {
2588
- throw new ZapierApiError(
2589
- `Failed to get action fields: ${needsData.errors?.join(", ") || "Unknown error"}`
2590
- );
2439
+ if ("error" in data) {
2440
+ if (typeof data.error === "string") {
2441
+ return data.error;
2442
+ }
2443
+ if (typeof data.error === "object" && data.error !== null) {
2444
+ if ("message" in data.error && typeof data.error.message === "string") {
2445
+ return data.error.message;
2446
+ }
2447
+ }
2448
+ try {
2449
+ return JSON.stringify(data.error);
2450
+ } catch {
2451
+ }
2591
2452
  }
2592
- const inputFields = (needsData.needs || []).map(
2593
- transformNeedToInputFieldItem
2594
- );
2595
- return {
2596
- data: inputFields,
2597
- nextCursor: void 0
2598
- // No pagination needed since we return all input fields
2599
- };
2600
- },
2601
- ListInputFieldsSchema
2602
- );
2603
- return {
2604
- listInputFields,
2605
- context: {
2606
- meta: {
2607
- listInputFields: {
2608
- categories: ["action"],
2609
- inputSchema: ListInputFieldsSchema
2453
+ if ("errors" in data && Array.isArray(data.errors)) {
2454
+ if (this.isApiErrorArray(data.errors)) {
2455
+ return data.errors[0].detail || data.errors[0].title;
2610
2456
  }
2611
2457
  }
2612
2458
  }
2613
- };
2614
- };
2615
-
2616
- // src/plugins/request/index.ts
2617
- function transformUrlToRelayPath(url) {
2618
- const targetUrl = new URL(url);
2619
- const relayPath = `/relay/${targetUrl.host}${targetUrl.pathname}${targetUrl.search}${targetUrl.hash}`;
2620
- return relayPath;
2621
- }
2622
- var requestPlugin = ({ context }) => {
2623
- const request = createFunction(async function request2(options) {
2624
- const { api } = context;
2625
- const {
2626
- url,
2627
- method = "GET",
2628
- body,
2629
- headers: optionsHeaders,
2630
- authenticationId,
2631
- callbackUrl,
2632
- authenticationTemplate
2633
- } = options;
2634
- const relayPath = transformUrlToRelayPath(url);
2635
- const headers = {};
2636
- if (optionsHeaders) {
2637
- const headerEntries = optionsHeaders instanceof Headers ? Array.from(optionsHeaders.entries()) : Array.isArray(optionsHeaders) ? optionsHeaders : Object.entries(optionsHeaders);
2638
- for (const [key, value] of headerEntries) {
2639
- headers[key] = value;
2459
+ return void 0;
2460
+ }
2461
+ // Helper to parse API error response
2462
+ parseErrorResponse(errorInfo) {
2463
+ const fallbackMessage = `HTTP ${errorInfo.status}: ${errorInfo.statusText}`;
2464
+ try {
2465
+ if (typeof errorInfo.data === "string") {
2466
+ return { message: `${fallbackMessage}: ${errorInfo.data}` };
2467
+ }
2468
+ const errorMessage = this.extractErrorMessage(errorInfo.data) || fallbackMessage;
2469
+ if (this.hasErrorArray(errorInfo.data)) {
2470
+ if (this.isApiErrorArray(errorInfo.data.errors)) {
2471
+ return {
2472
+ message: errorMessage,
2473
+ errors: errorInfo.data.errors
2474
+ };
2475
+ } else {
2476
+ return {
2477
+ message: errorMessage,
2478
+ errors: errorInfo.data.errors.map((e) => ({
2479
+ status: errorInfo.status,
2480
+ code: String(errorInfo.status),
2481
+ title: errorInfo.statusText,
2482
+ detail: JSON.stringify(e)
2483
+ }))
2484
+ };
2485
+ }
2640
2486
  }
2487
+ return { message: errorMessage };
2488
+ } catch {
2489
+ return { message: fallbackMessage };
2641
2490
  }
2642
- if (authenticationId) {
2643
- headers["X-Relay-Authentication-Id"] = authenticationId.toString();
2491
+ }
2492
+ // Check if this is a path that needs subdomain routing
2493
+ // e.g. /relay/workflows -> relay.zapier.com/workflows
2494
+ applySubdomainBehavior(path) {
2495
+ const pathSegments = path.split("/").filter(Boolean);
2496
+ if (pathSegments.length > 0 && pathSegments[0] in SubdomainConfigMap) {
2497
+ const domainPrefix = pathSegments[0];
2498
+ const subdomainConfig = SubdomainConfigMap[domainPrefix];
2499
+ const originalBaseUrl = new URL(this.options.baseUrl);
2500
+ const finalBaseUrl = `https://${domainPrefix}.${originalBaseUrl.hostname}`;
2501
+ const pathWithoutPrefix = "/" + pathSegments.slice(1).join("/");
2502
+ return { url: new URL(pathWithoutPrefix, finalBaseUrl), subdomainConfig };
2644
2503
  }
2645
- if (callbackUrl) {
2646
- headers["X-Relay-Callback-Url"] = callbackUrl;
2504
+ return {
2505
+ url: new URL(path, this.options.baseUrl),
2506
+ subdomainConfig: void 0
2507
+ };
2508
+ }
2509
+ // Helper to build full URLs and return routing info
2510
+ buildUrl(path, searchParams) {
2511
+ const { url, subdomainConfig } = this.applySubdomainBehavior(path);
2512
+ if (searchParams) {
2513
+ Object.entries(searchParams).forEach(([key, value]) => {
2514
+ url.searchParams.set(key, value);
2515
+ });
2516
+ }
2517
+ return { url: url.toString(), subdomainConfig };
2518
+ }
2519
+ // Helper to build headers
2520
+ async buildHeaders(options = {}, subdomainConfig) {
2521
+ const headers = new Headers(options.headers ?? {});
2522
+ const authToken = await this.getAuthToken();
2523
+ if (authToken) {
2524
+ const authHeaderName = subdomainConfig?.authHeader || "Authorization";
2525
+ headers.set(authHeaderName, getAuthorizationHeader(authToken));
2526
+ }
2527
+ if (options.authRequired) {
2528
+ if (headers.get("Authorization") == null && authToken == null) {
2529
+ throw new ZapierAuthenticationError(
2530
+ `Authentication required but no token available. Please set ZAPIER_TOKEN, or run the 'login' command with the CLI.`
2531
+ );
2532
+ }
2647
2533
  }
2648
- if (authenticationTemplate) {
2649
- headers["X-Authentication-Template"] = authenticationTemplate;
2534
+ return headers;
2535
+ }
2536
+ // Helper to perform HTTP requests with JSON handling
2537
+ async fetchJson(method, path, data, options = {}) {
2538
+ const headers = { ...options.headers };
2539
+ if (data && typeof data === "object") {
2540
+ headers["Content-Type"] = "application/json";
2650
2541
  }
2651
- return await api.fetch(relayPath, {
2542
+ const wasMissingAuthToken = options.authRequired && await this.getAuthToken() == null;
2543
+ const response = await this.plainFetch(path, {
2544
+ ...options,
2652
2545
  method,
2653
- body,
2546
+ body: data != null ? JSON.stringify(data) : void 0,
2654
2547
  headers
2655
2548
  });
2656
- }, RelayRequestSchema);
2549
+ const result = await this.handleResponse({
2550
+ response,
2551
+ customErrorHandler: options.customErrorHandler,
2552
+ wasMissingAuthToken
2553
+ });
2554
+ if (typeof result === "string") {
2555
+ throw new ZapierValidationError(
2556
+ `Response could not be parsed as JSON: ${result}`
2557
+ );
2558
+ }
2559
+ return result;
2560
+ }
2561
+ // Plain fetch method for API paths (must start with /)
2562
+ async plainFetch(path, fetchOptions) {
2563
+ if (!path.startsWith("/")) {
2564
+ throw new ZapierValidationError(
2565
+ `plainFetch expects a path starting with '/', got: ${path}`
2566
+ );
2567
+ }
2568
+ if (fetchOptions?.body && typeof fetchOptions.body === "object") {
2569
+ fetchOptions.body = JSON.stringify(fetchOptions.body);
2570
+ }
2571
+ const { url, subdomainConfig } = this.buildUrl(
2572
+ path,
2573
+ fetchOptions?.searchParams
2574
+ );
2575
+ const builtHeaders = await this.buildHeaders(
2576
+ fetchOptions,
2577
+ subdomainConfig
2578
+ );
2579
+ const inputHeaders = new Headers(fetchOptions?.headers ?? {});
2580
+ const mergedHeaders = new Headers();
2581
+ builtHeaders.forEach((value, key) => {
2582
+ mergedHeaders.set(key, value);
2583
+ });
2584
+ inputHeaders.forEach((value, key) => {
2585
+ mergedHeaders.set(key, value);
2586
+ });
2587
+ return await this.options.fetch(url, {
2588
+ ...fetchOptions,
2589
+ headers: mergedHeaders
2590
+ });
2591
+ }
2592
+ };
2593
+ var createZapierApi = (options) => {
2594
+ const {
2595
+ baseUrl,
2596
+ token,
2597
+ getToken,
2598
+ debug = false,
2599
+ fetch: originalFetch = globalThis.fetch,
2600
+ onEvent
2601
+ } = options;
2602
+ const debugLog = createDebugLogger(debug);
2603
+ const debugFetch = createDebugFetch({ originalFetch, debugLog });
2604
+ return new ZapierApiClient({
2605
+ baseUrl,
2606
+ token,
2607
+ getToken,
2608
+ debug,
2609
+ fetch: debugFetch,
2610
+ onEvent
2611
+ });
2612
+ };
2613
+
2614
+ // src/plugins/api/index.ts
2615
+ var apiPlugin = (params) => {
2616
+ const {
2617
+ fetch: customFetch = globalThis.fetch,
2618
+ baseUrl = "https://zapier.com",
2619
+ token,
2620
+ getToken,
2621
+ onEvent,
2622
+ debug = false
2623
+ } = params.context.options;
2624
+ const api = createZapierApi({
2625
+ baseUrl,
2626
+ token,
2627
+ getToken,
2628
+ debug,
2629
+ fetch: customFetch,
2630
+ onEvent
2631
+ });
2657
2632
  return {
2658
- request,
2659
2633
  context: {
2660
- meta: {
2661
- request: {
2662
- categories: ["http"],
2663
- inputSchema: RelayRequestSchema
2664
- }
2665
- }
2634
+ api
2635
+ // Provide API client in context for other plugins to use
2666
2636
  }
2667
2637
  };
2668
2638
  };
2669
- var ManifestSchema = z.object({
2670
- apps: z.record(
2671
- z.string(),
2672
- z.object({
2673
- implementationName: z.string().describe(
2674
- "Base implementation name without version (e.g., 'SlackCLIAPI')"
2675
- ),
2676
- version: z.string().describe("Version string (e.g., '1.21.1')")
2677
- })
2678
- )
2679
- }).describe("Manifest mapping app keys to version information");
2680
- z.object({
2681
- manifestPath: z.string().optional().describe("Path to manifest file"),
2682
- manifest: z.record(
2683
- z.string(),
2684
- z.object({
2685
- implementationName: z.string(),
2686
- version: z.string().optional()
2687
- })
2688
- ).optional().describe("Direct manifest object")
2689
- });
2690
2639
 
2691
- // src/plugins/manifest/index.ts
2692
- function parseManifestContent(content, source) {
2693
- try {
2694
- const parsed = JSON.parse(content);
2695
- if (parsed?.apps && typeof parsed?.apps === "object") {
2696
- const result = ManifestSchema.safeParse(parsed);
2697
- if (result.success) {
2698
- return result.data;
2640
+ // src/resolvers/appKey.ts
2641
+ var appKeyResolver = {
2642
+ type: "static",
2643
+ inputType: "text",
2644
+ placeholder: "Enter app key (e.g., 'SlackCLIAPI' or slug like 'github')"
2645
+ };
2646
+
2647
+ // src/resolvers/actionType.ts
2648
+ var actionTypeResolver = {
2649
+ type: "dynamic",
2650
+ depends: ["appKey"],
2651
+ fetch: async (sdk, resolvedParams) => {
2652
+ const actionsResponse = await sdk.listActions({
2653
+ appKey: resolvedParams.appKey
2654
+ });
2655
+ const types = [
2656
+ ...new Set(actionsResponse.data.map((action) => action.action_type))
2657
+ ];
2658
+ return types.map((type) => ({ key: type, name: type }));
2659
+ },
2660
+ prompt: (types) => ({
2661
+ type: "list",
2662
+ name: "actionType",
2663
+ message: "Select action type:",
2664
+ choices: types.map((type) => ({
2665
+ name: type.name,
2666
+ value: type.key
2667
+ }))
2668
+ })
2669
+ };
2670
+
2671
+ // src/resolvers/actionKey.ts
2672
+ var actionKeyResolver = {
2673
+ type: "dynamic",
2674
+ depends: ["appKey", "actionType"],
2675
+ fetch: async (sdk, resolvedParams) => {
2676
+ const actionsResponse = await sdk.listActions({
2677
+ appKey: resolvedParams.appKey
2678
+ });
2679
+ return actionsResponse.data.filter(
2680
+ (action) => action.action_type === resolvedParams.actionType
2681
+ );
2682
+ },
2683
+ prompt: (actions) => ({
2684
+ type: "list",
2685
+ name: "actionKey",
2686
+ message: "Select action:",
2687
+ choices: actions.map((action) => ({
2688
+ name: `${action.title || action.name || action.key} - ${action.description || "No description"}`,
2689
+ value: action.key
2690
+ }))
2691
+ })
2692
+ };
2693
+
2694
+ // src/resolvers/authenticationId.ts
2695
+ var authenticationIdResolver = {
2696
+ type: "dynamic",
2697
+ depends: ["appKey"],
2698
+ fetch: async (sdk, resolvedParams) => {
2699
+ const myAuths = await sdk.listAuthentications({
2700
+ appKey: resolvedParams.appKey,
2701
+ maxItems: 1e3,
2702
+ owner: "me"
2703
+ });
2704
+ const allAuths = await sdk.listAuthentications({
2705
+ appKey: resolvedParams.appKey,
2706
+ maxItems: 1e3
2707
+ });
2708
+ const otherAuths = allAuths.data.filter(
2709
+ (auth) => !myAuths.data.some((myAuth) => myAuth.id === auth.id)
2710
+ );
2711
+ return [...myAuths.data, ...otherAuths];
2712
+ },
2713
+ prompt: (auths, params) => ({
2714
+ type: "list",
2715
+ name: "authenticationId",
2716
+ message: `Select authentication for ${params.appKey}:`,
2717
+ choices: [
2718
+ ...auths.map((auth) => ({
2719
+ name: `${auth.title || auth.label || "Authentication"} (ID: ${auth.id})`,
2720
+ value: auth.id
2721
+ })),
2722
+ {
2723
+ name: "\u2197 Skip authentication (may fail)",
2724
+ value: null
2699
2725
  }
2700
- console.warn(`\u26A0\uFE0F Invalid manifest format in ${source}: ${result.error}`);
2726
+ ]
2727
+ })
2728
+ };
2729
+
2730
+ // src/resolvers/inputs.ts
2731
+ var inputsResolver = {
2732
+ type: "fields",
2733
+ depends: ["appKey", "actionKey", "actionType", "authenticationId"],
2734
+ fetch: async (sdk, resolvedParams) => {
2735
+ const fieldsResponse = await sdk.listInputFields({
2736
+ appKey: resolvedParams.appKey,
2737
+ actionKey: resolvedParams.actionKey,
2738
+ actionType: resolvedParams.actionType,
2739
+ authenticationId: resolvedParams.authenticationId,
2740
+ inputs: resolvedParams.inputs
2741
+ // Pass along currently resolved inputs
2742
+ });
2743
+ return fieldsResponse.data;
2744
+ }
2745
+ };
2746
+
2747
+ // src/resolvers/index.ts
2748
+ var resolverRegistry = {
2749
+ appKey: appKeyResolver,
2750
+ actionType: actionTypeResolver,
2751
+ actionKey: actionKeyResolver,
2752
+ authenticationId: authenticationIdResolver,
2753
+ inputs: inputsResolver
2754
+ };
2755
+ function getResolver(name) {
2756
+ return resolverRegistry[name];
2757
+ }
2758
+ function getResolversForMissingParams(missingParams) {
2759
+ const resolvers = {};
2760
+ for (const param of missingParams) {
2761
+ const resolver = resolverRegistry[param];
2762
+ if (resolver) {
2763
+ resolvers[param] = resolver;
2701
2764
  }
2702
- return null;
2703
- } catch (error) {
2704
- console.warn(`\u26A0\uFE0F Failed to parse manifest from ${source}:`, error);
2705
- return null;
2706
2765
  }
2766
+ return resolvers;
2707
2767
  }
2708
- function loadManifestFromFile(filePath) {
2709
- try {
2710
- const resolvedPath = resolve(filePath);
2711
- const content = readFileSync(resolvedPath, "utf8");
2712
- return parseManifestContent(content, resolvedPath);
2713
- } catch {
2714
- console.warn(`\u26A0\uFE0F Failed to load manifest from ${filePath}`);
2715
- return null;
2716
- }
2768
+ function hasResolver(paramName) {
2769
+ return paramName in resolverRegistry;
2717
2770
  }
2718
- var emitWarning = (appKey) => {
2719
- console.warn(
2720
- `
2721
- ${"\u26A0\uFE0F".padEnd(3)} ${"WARNING".padEnd(8)} No manifest version found for '${appKey}'`
2722
- );
2723
- console.warn(
2724
- ` ${"\u21B3".padEnd(3)} Using a manifest ensures version locking and prevents unexpected behavior due to version changes.`
2725
- );
2726
- console.warn(
2727
- ` ${"\u21B3".padEnd(3)} Generate/update the manifest with: \`zapier-sdk lock-version ${appKey}\`
2728
- `
2729
- );
2730
- };
2731
- var manifestPlugin = (params) => {
2732
- const { sdk, context } = params;
2733
- const { api, options } = context;
2734
- const { manifestPath = ".zapierrc", manifest } = options || {};
2735
- const resolvedManifest = (() => {
2736
- if (manifest) {
2737
- return manifest;
2738
- }
2739
- if (manifestPath) {
2740
- return loadManifestFromFile(manifestPath);
2741
- }
2742
- return null;
2743
- })();
2744
- const getManifestEntry = (appKey) => {
2745
- return resolvedManifest?.apps?.[appKey] || null;
2746
- };
2747
- const getImplementation = async (appKey) => {
2748
- let selectedApi = null;
2749
- const manifestImplementation = resolvedManifest?.apps?.[appKey];
2750
- const [versionlessAppKey, version] = splitVersionedKey(appKey);
2751
- if (version) {
2752
- selectedApi = `${versionlessAppKey}@${version}`;
2753
- } else if (manifestImplementation) {
2754
- selectedApi = `${manifestImplementation.implementationName}@${manifestImplementation.version || "latest"}`;
2755
- }
2756
- if (selectedApi) {
2757
- const searchParams = {
2758
- selected_apis: selectedApi
2759
- };
2760
- const implementationData = await api.get(
2761
- "/api/v4/implementations/",
2762
- {
2763
- searchParams
2764
- }
2765
- );
2766
- const implementationResults = implementationData.results[0];
2767
- if (!implementationResults) return null;
2768
- return normalizeImplementationToAppItem(implementationResults);
2769
- }
2770
- emitWarning(appKey);
2771
- const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2772
- const apps = [];
2773
- for await (const app2 of appsIterator) {
2774
- apps.push(app2);
2775
- break;
2776
- }
2777
- if (apps.length === 0) {
2778
- return null;
2771
+ function getResolvableParams() {
2772
+ return Object.keys(resolverRegistry);
2773
+ }
2774
+ function getResolutionOrder(paramName, resolved = /* @__PURE__ */ new Set()) {
2775
+ const resolver = getResolver(paramName);
2776
+ if (!resolver || resolver.type === "static") {
2777
+ return [paramName];
2778
+ }
2779
+ const order = [];
2780
+ if ("depends" in resolver && resolver.depends) {
2781
+ for (const dependency of resolver.depends) {
2782
+ if (!resolved.has(dependency)) {
2783
+ order.push(...getResolutionOrder(dependency, resolved));
2784
+ resolved.add(dependency);
2785
+ }
2779
2786
  }
2780
- const app = apps[0];
2781
- return app;
2782
- };
2783
- const getVersionedImplementationId = async (appKey) => {
2784
- const manifestEntry = getManifestEntry(appKey);
2785
- if (manifestEntry) {
2786
- return `${manifestEntry.implementationName}@${manifestEntry.version || "latest"}`;
2787
+ }
2788
+ if (!resolved.has(paramName)) {
2789
+ order.push(paramName);
2790
+ resolved.add(paramName);
2791
+ }
2792
+ return order;
2793
+ }
2794
+ function getResolutionOrderForParams(paramNames) {
2795
+ const resolved = /* @__PURE__ */ new Set();
2796
+ const order = [];
2797
+ for (const paramName of paramNames) {
2798
+ const paramOrder = getResolutionOrder(paramName, resolved);
2799
+ for (const param of paramOrder) {
2800
+ if (!order.includes(param)) {
2801
+ order.push(param);
2802
+ }
2787
2803
  }
2788
- const implementation = await getImplementation(appKey);
2789
- if (!implementation) return null;
2790
- return implementation.current_implementation_id;
2791
- };
2792
- return {
2793
- context: {
2794
- manifest: resolvedManifest,
2795
- getVersionedImplementationId,
2796
- getManifestEntry,
2797
- getImplementation
2804
+ }
2805
+ return order;
2806
+ }
2807
+
2808
+ // src/plugins/registry/index.ts
2809
+ var registryPlugin = ({ sdk, context }) => {
2810
+ const metaKeys = Object.keys(context.meta || {});
2811
+ const categoryDefinitions = {
2812
+ account: {
2813
+ title: "Account"
2814
+ },
2815
+ app: {
2816
+ title: "App",
2817
+ titlePlural: "Apps"
2818
+ },
2819
+ authentication: {
2820
+ title: "Authentication"
2821
+ },
2822
+ action: {
2823
+ title: "Action"
2824
+ },
2825
+ http: {
2826
+ title: "HTTP Request"
2827
+ },
2828
+ utility: {
2829
+ title: "Utility",
2830
+ titlePlural: "Utilities"
2831
+ },
2832
+ other: {
2833
+ title: "Other"
2798
2834
  }
2799
2835
  };
2800
- };
2801
- var LockVersionSchema = z.object({
2802
- appKey: z.string().describe("The app key to lock version for (e.g., 'slack', 'gmail')")
2803
- });
2804
- var lockVersionPlugin = ({ sdk }) => {
2805
- const lockVersion = createFunction(
2806
- async function lockVersion2(options) {
2807
- const { appKey, configPath = ".zapierrc" } = options;
2808
- const resolvedPath = resolve(configPath);
2809
- const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2810
- const apps = [];
2811
- for await (const app2 of appsIterator) {
2812
- apps.push(app2);
2813
- break;
2814
- }
2815
- const app = apps[0];
2816
- const currentImplementationId = app.current_implementation_id;
2817
- const [implementationName, version] = currentImplementationId.split("@");
2818
- if (!implementationName || !version) {
2819
- throw new Error(
2820
- `Invalid implementation ID format: ${currentImplementationId}. Expected format: <implementationName>@<version>`
2821
- );
2822
- }
2823
- let config = { apps: {} };
2824
- if (existsSync(resolvedPath)) {
2825
- try {
2826
- const configContent = readFileSync(resolvedPath, "utf8");
2827
- config = JSON.parse(configContent);
2828
- if (!config.apps) {
2829
- config.apps = {};
2830
- }
2831
- } catch (error) {
2832
- console.warn(
2833
- `\u26A0\uFE0F Failed to parse existing config file, creating new one: ${error}`
2834
- );
2835
- config = { apps: {} };
2836
- }
2837
- }
2838
- config.apps[appKey] = {
2839
- implementationName,
2840
- version
2841
- };
2842
- writeFileSync(resolvedPath, JSON.stringify(config, null, 2));
2843
- return {
2844
- data: {
2845
- ...app,
2846
- implementationName,
2847
- version
2848
- },
2849
- configPath: resolvedPath
2850
- };
2851
- },
2852
- LockVersionSchema.extend({
2853
- configPath: z.string().optional().describe("Path to .zapierrc file (defaults to '.zapierrc')")
2854
- })
2855
- );
2836
+ const functions = metaKeys.filter((key) => typeof sdk[key] === "function").map((key) => {
2837
+ return {
2838
+ ...context.meta[key],
2839
+ categories: context.meta[key].categories || [],
2840
+ name: key
2841
+ };
2842
+ }).sort((a, b) => a.name.localeCompare(b.name));
2843
+ const knownCategories = Object.keys(categoryDefinitions);
2844
+ const categories = knownCategories.sort((a, b) => {
2845
+ if (a === "other") return 1;
2846
+ if (b === "other") return -1;
2847
+ const titleA = categoryDefinitions[a].title;
2848
+ const titleB = categoryDefinitions[b].title;
2849
+ return titleA.localeCompare(titleB);
2850
+ }).map((categoryKey) => {
2851
+ const categoryFunctions = functions.filter(
2852
+ (f) => f.categories.includes(categoryKey) || // If the category is "other" and the function is not in any other category, include it
2853
+ categoryKey === "other" && !f.categories.some((c) => knownCategories.includes(c))
2854
+ ).map((f) => f.name).sort();
2855
+ const definition = categoryDefinitions[categoryKey];
2856
+ const title = definition.title;
2857
+ return {
2858
+ key: categoryKey,
2859
+ title,
2860
+ titlePlural: definition.titlePlural ?? `${title}s`,
2861
+ functions: categoryFunctions
2862
+ };
2863
+ });
2864
+ function getRegistry() {
2865
+ return {
2866
+ functions,
2867
+ categories
2868
+ };
2869
+ }
2856
2870
  return {
2857
- lockVersion,
2858
- context: {
2859
- meta: {
2860
- lockVersion: {
2861
- categories: ["utility"],
2862
- inputSchema: LockVersionSchema
2863
- }
2864
- }
2865
- }
2871
+ getRegistry
2866
2872
  };
2867
2873
  };
2868
2874
 
@@ -2914,8 +2920,11 @@ function createSdk(options = {}, initialSdk = {}, initialContext = { meta: {} })
2914
2920
  }
2915
2921
  };
2916
2922
  }
2923
+ function createZapierSdkWithoutRegistry(options = {}) {
2924
+ return createSdk(options).addPlugin(apiPlugin).addPlugin(listAppsPlugin).addPlugin(manifestPlugin).addPlugin(getAppPlugin).addPlugin(listActionsPlugin).addPlugin(getActionPlugin).addPlugin(listInputFieldsPlugin).addPlugin(runActionPlugin).addPlugin(lockVersionPlugin).addPlugin(listAuthenticationsPlugin).addPlugin(getAuthenticationPlugin).addPlugin(findFirstAuthenticationPlugin).addPlugin(findUniqueAuthenticationPlugin).addPlugin(requestPlugin).addPlugin(fetchPlugin).addPlugin(appsPlugin).addPlugin(getProfilePlugin);
2925
+ }
2917
2926
  function createZapierSdk(options = {}) {
2918
- return createSdk(options).addPlugin(apiPlugin).addPlugin(listAppsPlugin).addPlugin(manifestPlugin).addPlugin(getAppPlugin).addPlugin(listActionsPlugin).addPlugin(getActionPlugin).addPlugin(listInputFieldsPlugin).addPlugin(runActionPlugin).addPlugin(lockVersionPlugin).addPlugin(listAuthenticationsPlugin).addPlugin(getAuthenticationPlugin).addPlugin(findFirstAuthenticationPlugin).addPlugin(findUniqueAuthenticationPlugin).addPlugin(requestPlugin).addPlugin(fetchPlugin).addPlugin(appsPlugin).addPlugin(getProfilePlugin).addPlugin(registryPlugin);
2927
+ return createZapierSdkWithoutRegistry(options).addPlugin(registryPlugin);
2919
2928
  }
2920
2929
 
2921
- export { ActionKeyPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AuthenticationIdPropertySchema, DebugPropertySchema, InputsPropertySchema, LimitPropertySchema, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, RelayFetchSchema, RelayRequestSchema, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierError, ZapierNotFoundError, ZapierResourceNotFoundError, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, appKeyResolver, appsPlugin, authenticationIdResolver, createSdk, createZapierSdk, fetchPlugin, formatErrorMessage, getResolutionOrder, getResolutionOrderForParams, getResolvableParams, getResolver, getResolversForMissingParams, getTokenFromCliLogin, getTokenFromEnv, getTokenFromEnvOrConfig, hasResolver, inputsResolver, isPositional, resolverRegistry };
2930
+ export { ActionKeyPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AuthenticationIdPropertySchema, DebugPropertySchema, InputsPropertySchema, LimitPropertySchema, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, RelayFetchSchema, RelayRequestSchema, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierError, ZapierNotFoundError, ZapierResourceNotFoundError, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, authenticationIdResolver, createFunction, createSdk, createZapierSdk, createZapierSdkWithoutRegistry, fetchPlugin, findFirstAuthenticationPlugin, findUniqueAuthenticationPlugin, formatErrorMessage, getActionPlugin, getAppPlugin, getAuthenticationPlugin, getProfilePlugin, getResolutionOrder, getResolutionOrderForParams, getResolvableParams, getResolver, getResolversForMissingParams, getTokenFromCliLogin, getTokenFromEnv, getTokenFromEnvOrConfig, hasResolver, inputsResolver, isPositional, listActionsPlugin, listAppsPlugin, listAuthenticationsPlugin, listInputFieldsPlugin, loadManifestFromFile, lockVersionPlugin, manifestPlugin, registryPlugin, requestPlugin, resolverRegistry, runActionPlugin };