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