@zapier/zapier-sdk 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +10 -33
  3. package/dist/api/client.d.ts.map +1 -1
  4. package/dist/api/client.js +1 -2
  5. package/dist/api/polling.d.ts +36 -6
  6. package/dist/api/polling.d.ts.map +1 -1
  7. package/dist/api/polling.js +132 -28
  8. package/dist/api/polling.test.d.ts +2 -0
  9. package/dist/api/polling.test.d.ts.map +1 -0
  10. package/dist/api/polling.test.js +318 -0
  11. package/dist/api/types.d.ts +1 -2
  12. package/dist/api/types.d.ts.map +1 -1
  13. package/dist/index.cjs +489 -252
  14. package/dist/index.d.mts +182 -187
  15. package/dist/index.d.ts +1 -2
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +0 -1
  18. package/dist/index.mjs +486 -251
  19. package/dist/plugins/apps/index.d.ts +4 -0
  20. package/dist/plugins/apps/index.d.ts.map +1 -1
  21. package/dist/plugins/getApp/index.d.ts +2 -7
  22. package/dist/plugins/getApp/index.d.ts.map +1 -1
  23. package/dist/plugins/getApp/index.js +9 -9
  24. package/dist/plugins/getApp/index.test.js +1 -1
  25. package/dist/plugins/getAuthentication/index.test.js +1 -1
  26. package/dist/plugins/listActions/index.d.ts +2 -4
  27. package/dist/plugins/listActions/index.d.ts.map +1 -1
  28. package/dist/plugins/listActions/index.js +1 -1
  29. package/dist/plugins/listActions/index.test.js +4 -4
  30. package/dist/plugins/listApps/index.d.ts +4 -7
  31. package/dist/plugins/listApps/index.d.ts.map +1 -1
  32. package/dist/plugins/listApps/index.js +33 -17
  33. package/dist/plugins/listApps/index.test.js +22 -2
  34. package/dist/plugins/listAuthentications/index.d.ts +2 -4
  35. package/dist/plugins/listAuthentications/index.d.ts.map +1 -1
  36. package/dist/plugins/listAuthentications/index.js +4 -0
  37. package/dist/plugins/listAuthentications/index.test.js +39 -13
  38. package/dist/plugins/listAuthentications/schemas.d.ts +3 -0
  39. package/dist/plugins/listAuthentications/schemas.d.ts.map +1 -1
  40. package/dist/plugins/listAuthentications/schemas.js +4 -0
  41. package/dist/plugins/manifest/index.d.ts +25 -9
  42. package/dist/plugins/manifest/index.d.ts.map +1 -1
  43. package/dist/plugins/manifest/index.js +239 -67
  44. package/dist/plugins/manifest/index.test.js +426 -171
  45. package/dist/plugins/manifest/schemas.d.ts +5 -1
  46. package/dist/plugins/manifest/schemas.d.ts.map +1 -1
  47. package/dist/plugins/manifest/schemas.js +1 -0
  48. package/dist/sdk.d.ts +5 -11
  49. package/dist/sdk.d.ts.map +1 -1
  50. package/dist/sdk.js +1 -4
  51. package/dist/types/plugin.d.ts +1 -0
  52. package/dist/types/plugin.d.ts.map +1 -1
  53. package/dist/types/sdk.d.ts +6 -3
  54. package/dist/types/sdk.d.ts.map +1 -1
  55. package/dist/utils/domain-utils.d.ts +16 -0
  56. package/dist/utils/domain-utils.d.ts.map +1 -1
  57. package/dist/utils/domain-utils.js +46 -27
  58. package/dist/utils/domain-utils.test.js +157 -3
  59. package/dist/utils/file-utils.d.ts +4 -0
  60. package/dist/utils/file-utils.d.ts.map +1 -0
  61. package/dist/utils/file-utils.js +74 -0
  62. package/dist/utils/file-utils.test.d.ts +2 -0
  63. package/dist/utils/file-utils.test.d.ts.map +1 -0
  64. package/dist/utils/file-utils.test.js +51 -0
  65. package/package.json +1 -1
  66. package/src/api/client.ts +5 -4
  67. package/src/api/polling.test.ts +405 -0
  68. package/src/api/polling.ts +224 -44
  69. package/src/api/types.ts +1 -2
  70. package/src/index.ts +1 -1
  71. package/src/plugins/apps/index.ts +9 -2
  72. package/src/plugins/getApp/index.test.ts +1 -1
  73. package/src/plugins/getApp/index.ts +12 -14
  74. package/src/plugins/getAuthentication/index.test.ts +1 -1
  75. package/src/plugins/listActions/index.test.ts +8 -7
  76. package/src/plugins/listActions/index.ts +3 -3
  77. package/src/plugins/listApps/index.test.ts +23 -2
  78. package/src/plugins/listApps/index.ts +46 -25
  79. package/src/plugins/listAuthentications/index.test.ts +52 -15
  80. package/src/plugins/listAuthentications/index.ts +7 -2
  81. package/src/plugins/listAuthentications/schemas.ts +4 -0
  82. package/src/plugins/manifest/index.test.ts +503 -197
  83. package/src/plugins/manifest/index.ts +338 -82
  84. package/src/plugins/manifest/schemas.ts +9 -2
  85. package/src/sdk.ts +1 -5
  86. package/src/types/plugin.ts +3 -0
  87. package/src/types/sdk.ts +26 -21
  88. package/src/utils/domain-utils.test.ts +196 -2
  89. package/src/utils/domain-utils.ts +68 -35
  90. package/src/utils/file-utils.test.ts +73 -0
  91. package/src/utils/file-utils.ts +94 -0
  92. package/tsconfig.tsbuildinfo +1 -1
  93. package/dist/plugins/lockVersion/index.d.ts +0 -24
  94. package/dist/plugins/lockVersion/index.d.ts.map +0 -1
  95. package/dist/plugins/lockVersion/index.js +0 -72
  96. package/dist/plugins/lockVersion/index.test.d.ts +0 -2
  97. package/dist/plugins/lockVersion/index.test.d.ts.map +0 -1
  98. package/dist/plugins/lockVersion/index.test.js +0 -129
  99. package/dist/plugins/lockVersion/schemas.d.ts +0 -10
  100. package/dist/plugins/lockVersion/schemas.d.ts.map +0 -1
  101. package/dist/plugins/lockVersion/schemas.js +0 -6
  102. package/src/plugins/lockVersion/index.test.ts +0 -176
  103. package/src/plugins/lockVersion/index.ts +0 -112
  104. package/src/plugins/lockVersion/schemas.ts +0 -9
package/dist/index.cjs CHANGED
@@ -1,8 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var zod = require('zod');
4
- var fs = require('fs');
5
- var path = require('path');
4
+ var promises = require('timers/promises');
6
5
 
7
6
  // src/types/properties.ts
8
7
  function withFormatter(schema, formatMeta) {
@@ -653,16 +652,6 @@ function splitVersionedKey(versionedKey) {
653
652
  }
654
653
  return [versionedKey, void 0];
655
654
  }
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
655
  function normalizeImplementationMetaToAppItem(implementationMeta) {
667
656
  const [selectedApi, appVersion] = splitVersionedKey(implementationMeta.id);
668
657
  return {
@@ -724,50 +713,8 @@ function normalizeActionItem(action) {
724
713
  type: "action"
725
714
  };
726
715
  }
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
- };
716
+ function isSlug(slug) {
717
+ return !!slug.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
771
718
  }
772
719
  function isSnakeCasedSlug(slug) {
773
720
  if (slug.match(/^_[0-9]/)) {
@@ -784,15 +731,54 @@ function dashifySnakeCasedSlug(slug) {
784
731
  }
785
732
  return slug.replace(/_/g, "-");
786
733
  }
734
+ function isUuid(appKey) {
735
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
736
+ appKey
737
+ );
738
+ }
739
+ function toAppLocator(appKey) {
740
+ const [appKeyWithoutVersion, version] = splitVersionedKey(appKey);
741
+ if (isUuid(appKeyWithoutVersion)) {
742
+ throw new Error(
743
+ `UUID app keys are not supported. Use app slug or implementation ID instead of: ${appKey}`
744
+ );
745
+ }
746
+ const slug = isSlug(appKeyWithoutVersion) ? appKeyWithoutVersion : isSnakeCasedSlug(appKeyWithoutVersion) ? dashifySnakeCasedSlug(appKeyWithoutVersion) : void 0;
747
+ return {
748
+ lookupAppKey: appKeyWithoutVersion,
749
+ slug,
750
+ implementationName: slug ? void 0 : appKeyWithoutVersion,
751
+ version
752
+ };
753
+ }
754
+ function isResolvedAppLocator(appLocator) {
755
+ return !!appLocator.implementationName;
756
+ }
757
+ function toImplementationId(appLocator) {
758
+ return `${appLocator.implementationName}@${appLocator.version || "latest"}`;
759
+ }
787
760
 
788
761
  // src/plugins/listApps/index.ts
789
762
  var listAppsPlugin = ({ context }) => {
790
763
  const listApps = createPaginatedFunction(async function listAppsPage(options) {
791
764
  const api = context.api;
792
765
  const opts = options;
793
- const appKeys = [...opts.appKeys ?? []].map(
794
- (key) => splitVersionedKey(key)[0]
795
- );
766
+ const appLocators = await context.resolveAppKeys({
767
+ appKeys: [...opts.appKeys ?? []]
768
+ });
769
+ const implementationNameToLocator = {};
770
+ for (const locator of appLocators) {
771
+ implementationNameToLocator[locator.implementationName] = [
772
+ ...implementationNameToLocator[locator.implementationName] ?? [],
773
+ locator
774
+ ];
775
+ }
776
+ const duplicatedLookupAppKeys = Object.keys(implementationNameToLocator).filter((key) => implementationNameToLocator[key].length > 1).map((key) => implementationNameToLocator[key]).flat().map((locator) => locator.lookupAppKey);
777
+ if (duplicatedLookupAppKeys.length > 0) {
778
+ throw new Error(
779
+ `Duplicate lookup app keys found: ${duplicatedLookupAppKeys.join(", ")}`
780
+ );
781
+ }
796
782
  if (opts.search) {
797
783
  const searchParams2 = {};
798
784
  searchParams2.term = opts.search;
@@ -805,11 +791,17 @@ var listAppsPlugin = ({ context }) => {
805
791
  const implementations = searchEnvelope.results.map(
806
792
  normalizeImplementationMetaToAppItem
807
793
  );
808
- const appKeysSet = new Set(appKeys);
794
+ const implementationNameSet = new Set(
795
+ appLocators.map((locator) => locator.implementationName)
796
+ );
809
797
  for (const implementation of implementations) {
810
- if (!appKeysSet.has(implementation.key)) {
811
- appKeysSet.add(implementation.key);
812
- appKeys.push(implementation.key);
798
+ const [implementationName] = splitVersionedKey(implementation.key);
799
+ if (!implementationNameSet.has(implementationName)) {
800
+ implementationNameSet.add(implementationName);
801
+ appLocators.push({
802
+ ...toAppLocator(implementation.key),
803
+ implementationName
804
+ });
813
805
  }
814
806
  }
815
807
  }
@@ -817,19 +809,13 @@ var listAppsPlugin = ({ context }) => {
817
809
  if (opts.pageSize) {
818
810
  searchParams.limit = opts.pageSize.toString();
819
811
  }
820
- searchParams.latest_only = "true";
812
+ if (appLocators.length === 0) {
813
+ searchParams.latest_only = "true";
814
+ }
821
815
  if (opts.cursor) {
822
816
  searchParams.offset = opts.cursor;
823
817
  }
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
- }
818
+ searchParams.selected_apis = appLocators.map((locator) => toImplementationId(locator)).join(",");
833
819
  const implementationsEnvelope = await api.get(
834
820
  "/api/v4/implementations-meta/lookup/",
835
821
  {
@@ -1476,6 +1462,7 @@ var ListAuthenticationsSchema = zod.z.object({
1476
1462
  appKey: AppKeyPropertySchema.optional().describe(
1477
1463
  "App key of authentications to list (e.g., 'SlackCLIAPI')"
1478
1464
  ),
1465
+ authenticationIds: zod.z.array(zod.z.string()).optional().describe("List of authentication IDs to filter by"),
1479
1466
  search: zod.z.string().optional().describe("Search term to filter authentications by title"),
1480
1467
  title: zod.z.string().optional().describe("Filter authentications by exact title match"),
1481
1468
  accountId: zod.z.string().optional().describe("Filter by account ID"),
@@ -1499,6 +1486,9 @@ var listAuthenticationsPlugin = ({ context }) => {
1499
1486
  searchParams.versionless_selected_api = versionlessSelectedApi;
1500
1487
  }
1501
1488
  }
1489
+ if (options.authenticationIds && options.authenticationIds.length > 0) {
1490
+ searchParams.ids = options.authenticationIds.join(",");
1491
+ }
1502
1492
  if (options.search) {
1503
1493
  searchParams.search = options.search;
1504
1494
  } else if (options.title) {
@@ -1571,17 +1561,17 @@ var GetAppSchema = withOutputSchema(
1571
1561
  );
1572
1562
 
1573
1563
  // src/plugins/getApp/index.ts
1574
- var getAppPlugin = ({ context }) => {
1564
+ var getAppPlugin = ({ sdk }) => {
1575
1565
  const getApp = createFunction(async function getApp2(options) {
1576
- const app = await context.getImplementation(options.appKey);
1577
- if (!app) {
1578
- throw new ZapierAppNotFoundError("App not found", {
1579
- appKey: options.appKey
1580
- });
1566
+ const appsIterator = sdk.listApps({ appKeys: [options.appKey] }).items();
1567
+ for await (const app of appsIterator) {
1568
+ return {
1569
+ data: app
1570
+ };
1581
1571
  }
1582
- return {
1583
- data: app
1584
- };
1572
+ throw new ZapierAppNotFoundError("App not found", {
1573
+ appKey: options.appKey
1574
+ });
1585
1575
  }, GetAppSchema);
1586
1576
  return {
1587
1577
  getApp,
@@ -1947,6 +1937,67 @@ var requestPlugin = ({ context }) => {
1947
1937
  }
1948
1938
  };
1949
1939
  };
1940
+
1941
+ // src/utils/file-utils.ts
1942
+ var inMemoryFiles = {};
1943
+ var fsPromises = null;
1944
+ var pathModule = null;
1945
+ async function loadFsPromises() {
1946
+ if (fsPromises) return fsPromises;
1947
+ try {
1948
+ fsPromises = await import('fs/promises');
1949
+ return fsPromises;
1950
+ } catch {
1951
+ return null;
1952
+ }
1953
+ }
1954
+ async function loadPathModule() {
1955
+ if (pathModule) return pathModule;
1956
+ try {
1957
+ pathModule = await import('path');
1958
+ return pathModule;
1959
+ } catch {
1960
+ return null;
1961
+ }
1962
+ }
1963
+ async function resolve(path, basePath = "/") {
1964
+ const pathModule2 = await loadPathModule();
1965
+ if (pathModule2) {
1966
+ return pathModule2.resolve(path);
1967
+ }
1968
+ if (path.startsWith("/")) {
1969
+ return path;
1970
+ }
1971
+ if (path.startsWith("./")) {
1972
+ const cleanPath = path.slice(2);
1973
+ return basePath.endsWith("/") ? basePath + cleanPath : basePath + "/" + cleanPath;
1974
+ }
1975
+ if (path.startsWith("../")) {
1976
+ const cleanPath = path.replace(/^(\.\.\/)+/, "");
1977
+ return basePath.endsWith("/") ? basePath + cleanPath : basePath + "/" + cleanPath;
1978
+ }
1979
+ return basePath.endsWith("/") ? basePath + path : basePath + "/" + path;
1980
+ }
1981
+ async function writeFile(filePath, content) {
1982
+ const fs = await loadFsPromises();
1983
+ if (fs) {
1984
+ await fs.writeFile(filePath, content, "utf8");
1985
+ return;
1986
+ }
1987
+ inMemoryFiles[filePath] = content;
1988
+ }
1989
+ async function readFile(filePath) {
1990
+ const fs = await loadFsPromises();
1991
+ if (fs) {
1992
+ return await fs.readFile(filePath, "utf8");
1993
+ }
1994
+ const content = inMemoryFiles[filePath];
1995
+ if (content !== void 0) {
1996
+ return content;
1997
+ }
1998
+ throw new Error(`File not found: ${filePath}`);
1999
+ }
2000
+ var DEFAULT_CONFIG_PATH = ".zapierrc";
1950
2001
  var ManifestSchema = zod.z.object({
1951
2002
  apps: zod.z.record(
1952
2003
  zod.z.string(),
@@ -1969,6 +2020,15 @@ zod.z.object({
1969
2020
  ).optional().describe("Direct manifest object")
1970
2021
  });
1971
2022
 
2023
+ // src/utils/array-utils.ts
2024
+ async function toArrayFromAsync(asyncIterable) {
2025
+ const result = [];
2026
+ for await (const item of asyncIterable) {
2027
+ result.push(item);
2028
+ }
2029
+ return result;
2030
+ }
2031
+
1972
2032
  // src/plugins/manifest/index.ts
1973
2033
  function parseManifestContent(content, source) {
1974
2034
  try {
@@ -1986,169 +2046,235 @@ function parseManifestContent(content, source) {
1986
2046
  return null;
1987
2047
  }
1988
2048
  }
1989
- function loadManifestFromFile(filePath) {
2049
+ async function readManifestFromFile(filePath) {
1990
2050
  try {
1991
- const resolvedPath = path.resolve(filePath);
1992
- const content = fs.readFileSync(resolvedPath, "utf8");
2051
+ const resolvedPath = await resolve(filePath);
2052
+ const content = await readFile(resolvedPath);
1993
2053
  return parseManifestContent(content, resolvedPath);
1994
2054
  } catch {
1995
- console.warn(`\u26A0\uFE0F Failed to load manifest from ${filePath}`);
2055
+ console.warn(`\u26A0\uFE0F Failed to read manifest from ${filePath}`);
1996
2056
  return null;
1997
2057
  }
1998
2058
  }
1999
- var emitWarning = (appKey) => {
2000
- console.warn(
2001
- `
2002
- ${"\u26A0\uFE0F".padEnd(3)} ${"WARNING".padEnd(8)} No manifest version found for '${appKey}'`
2003
- );
2004
- console.warn(
2005
- ` ${"\u21B3".padEnd(3)} Using a manifest ensures version locking and prevents unexpected behavior due to version changes.`
2059
+ async function writeManifestToFile(manifest, filePath) {
2060
+ const resolvedPath = await resolve(filePath);
2061
+ await writeFile(resolvedPath, JSON.stringify(manifest, null, 2));
2062
+ }
2063
+ async function getPreferredManifestEntryKey({
2064
+ appKey,
2065
+ api
2066
+ }) {
2067
+ const locator = toAppLocator(appKey);
2068
+ if (locator.slug) {
2069
+ return locator.slug;
2070
+ }
2071
+ if (locator.implementationName) {
2072
+ try {
2073
+ const implementationsEnvelope = await api.get(`/api/v4/implementations-meta/lookup/`, {
2074
+ searchParams: {
2075
+ selected_apis: locator.implementationName
2076
+ }
2077
+ });
2078
+ if (implementationsEnvelope.results.length > 0 && implementationsEnvelope.results[0].slug) {
2079
+ return implementationsEnvelope.results[0].slug;
2080
+ }
2081
+ } catch {
2082
+ }
2083
+ return locator.implementationName;
2084
+ }
2085
+ return locator.lookupAppKey;
2086
+ }
2087
+ async function listAppsForSlugsPage({
2088
+ slugs,
2089
+ cursor,
2090
+ api
2091
+ }) {
2092
+ const searchParams = {};
2093
+ if (slugs.length > 0) {
2094
+ searchParams.slugs = slugs.join(",");
2095
+ }
2096
+ if (cursor) {
2097
+ searchParams.offset = cursor;
2098
+ }
2099
+ const implementationsEnvelope = await api.get(
2100
+ "/api/v4/implementations-meta/lookup/",
2101
+ {
2102
+ searchParams
2103
+ }
2006
2104
  );
2007
- console.warn(
2008
- ` ${"\u21B3".padEnd(3)} Generate/update the manifest with: \`zapier-sdk lock-version ${appKey}\`
2009
- `
2105
+ return {
2106
+ data: implementationsEnvelope.results.map(
2107
+ normalizeImplementationMetaToAppItem
2108
+ ),
2109
+ nextCursor: extractCursor(implementationsEnvelope)
2110
+ };
2111
+ }
2112
+ function findManifestEntry({
2113
+ appKey,
2114
+ manifest
2115
+ }) {
2116
+ const [appKeyWithoutVersion] = splitVersionedKey(appKey);
2117
+ if (manifest.apps[appKeyWithoutVersion]) {
2118
+ return [appKeyWithoutVersion, manifest.apps[appKeyWithoutVersion]];
2119
+ }
2120
+ if (isSnakeCasedSlug(appKey)) {
2121
+ const slug = dashifySnakeCasedSlug(appKey);
2122
+ if (manifest.apps[slug]) {
2123
+ return [slug, manifest.apps[slug]];
2124
+ }
2125
+ }
2126
+ for (const [key, entry] of Object.entries(manifest.apps)) {
2127
+ if (entry.implementationName === appKeyWithoutVersion) {
2128
+ return [key, entry];
2129
+ }
2130
+ }
2131
+ return null;
2132
+ }
2133
+ async function resolveAppKeys({
2134
+ appKeys,
2135
+ api,
2136
+ manifest
2137
+ }) {
2138
+ const locators = appKeys.map(toAppLocator);
2139
+ const locatorsWithManifest = locators.map((locator) => {
2140
+ const manifestEntryResult = findManifestEntry({
2141
+ appKey: locator.lookupAppKey,
2142
+ manifest
2143
+ });
2144
+ if (manifestEntryResult) {
2145
+ const [, manifestEntry] = manifestEntryResult;
2146
+ const resolvedVersion = locator.version || manifestEntry.version;
2147
+ const resolvedLocator = {
2148
+ ...locator,
2149
+ implementationName: manifestEntry.implementationName,
2150
+ version: resolvedVersion
2151
+ };
2152
+ return resolvedLocator;
2153
+ }
2154
+ return locator;
2155
+ });
2156
+ const unresolvedLocators = locatorsWithManifest.filter(
2157
+ (locator) => !isResolvedAppLocator(locator)
2010
2158
  );
2011
- };
2159
+ const slugsToResolve = unresolvedLocators.map((locator) => locator.slug).filter((slug) => !!slug).filter((slug, index, array) => array.indexOf(slug) === index);
2160
+ if (slugsToResolve.length === 0) {
2161
+ return locatorsWithManifest.filter(isResolvedAppLocator);
2162
+ }
2163
+ const iterator = paginate(listAppsForSlugsPage, {
2164
+ slugs: slugsToResolve,
2165
+ api
2166
+ });
2167
+ const pages = await toArrayFromAsync(iterator);
2168
+ const apps = pages.flatMap((page) => page.data);
2169
+ const slugToAppData = /* @__PURE__ */ new Map();
2170
+ for (const app of apps) {
2171
+ if (app.slug) {
2172
+ slugToAppData.set(app.slug, app);
2173
+ }
2174
+ }
2175
+ const slugResolvedLocators = locatorsWithManifest.map((locator) => {
2176
+ if (isResolvedAppLocator(locator)) {
2177
+ return locator;
2178
+ }
2179
+ if (locator.slug) {
2180
+ const appData = slugToAppData.get(locator.slug);
2181
+ if (appData) {
2182
+ const manifestEntryByImplementationName = findManifestEntry({
2183
+ appKey: appData.key,
2184
+ // appData.key is the implementation name
2185
+ manifest
2186
+ });
2187
+ let version = locator.version;
2188
+ if (!version) {
2189
+ version = manifestEntryByImplementationName ? manifestEntryByImplementationName[1].version || appData.version : appData.version;
2190
+ }
2191
+ return {
2192
+ ...locator,
2193
+ implementationName: appData.key,
2194
+ version
2195
+ };
2196
+ }
2197
+ }
2198
+ return locator;
2199
+ });
2200
+ return slugResolvedLocators.filter(isResolvedAppLocator);
2201
+ }
2012
2202
  var manifestPlugin = (params) => {
2013
- const { sdk, context } = params;
2203
+ const { context } = params;
2014
2204
  const { api, options } = context;
2015
- const { manifestPath = ".zapierrc", manifest } = options || {};
2205
+ const { manifestPath = DEFAULT_CONFIG_PATH, manifest } = options || {};
2016
2206
  let resolvedManifest;
2017
- function resolveManifest() {
2207
+ async function resolveManifest() {
2018
2208
  if (manifest) {
2019
2209
  return manifest;
2020
2210
  }
2021
2211
  if (manifestPath) {
2022
- return loadManifestFromFile(manifestPath);
2212
+ return await readManifestFromFile(manifestPath);
2023
2213
  }
2024
2214
  return null;
2025
2215
  }
2026
- const getResolvedManifest = () => {
2216
+ const getResolvedManifest = async () => {
2027
2217
  if (typeof resolvedManifest === "undefined") {
2028
- resolvedManifest = resolveManifest() ?? null;
2218
+ resolvedManifest = await resolveManifest() ?? null;
2029
2219
  }
2030
2220
  return resolvedManifest;
2031
2221
  };
2032
- const getManifestEntry = (appKey) => {
2033
- return getResolvedManifest()?.apps?.[appKey] || null;
2222
+ const getVersionedImplementationId = async (appKey) => {
2223
+ const resolvedApps = await resolveAppKeys({
2224
+ appKeys: [appKey],
2225
+ api,
2226
+ manifest: await getResolvedManifest() ?? { apps: {} }
2227
+ });
2228
+ const resolvedApp = resolvedApps[0];
2229
+ if (!resolvedApp) return null;
2230
+ return `${resolvedApp.implementationName}@${resolvedApp.version || "latest"}`;
2034
2231
  };
2035
- const getImplementation = async (appKey) => {
2036
- let selectedApi = null;
2037
- const manifestImplementation = getResolvedManifest()?.apps?.[appKey];
2038
- const [versionlessAppKey, version] = splitVersionedKey(appKey);
2039
- if (version) {
2040
- selectedApi = `${versionlessAppKey}@${version}`;
2041
- } else if (manifestImplementation) {
2042
- selectedApi = `${manifestImplementation.implementationName}@${manifestImplementation.version || "latest"}`;
2043
- }
2044
- if (selectedApi) {
2045
- const searchParams = {
2046
- selected_apis: selectedApi
2047
- };
2048
- const implementationData = await api.get(
2049
- "/api/v4/implementations/",
2050
- {
2051
- searchParams
2232
+ const updateManifestEntry = async (appKey, entry, configPath = DEFAULT_CONFIG_PATH) => {
2233
+ const manifest2 = await readManifestFromFile(configPath) || { apps: {} };
2234
+ let existingEntry = findManifestEntry({
2235
+ appKey,
2236
+ manifest: manifest2
2237
+ });
2238
+ if (!existingEntry) {
2239
+ try {
2240
+ const resolvedApps = await resolveAppKeys({
2241
+ appKeys: [appKey],
2242
+ api,
2243
+ manifest: manifest2
2244
+ });
2245
+ if (resolvedApps.length > 0) {
2246
+ const resolvedImplementationName = resolvedApps[0].implementationName;
2247
+ existingEntry = findManifestEntry({
2248
+ appKey: resolvedImplementationName,
2249
+ manifest: manifest2
2250
+ });
2052
2251
  }
2053
- );
2054
- const implementationResults = implementationData.results[0];
2055
- if (!implementationResults) return null;
2056
- return normalizeImplementationToAppItem(implementationResults);
2057
- }
2058
- emitWarning(appKey);
2059
- const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2060
- const apps = [];
2061
- for await (const app2 of appsIterator) {
2062
- apps.push(app2);
2063
- break;
2064
- }
2065
- if (apps.length === 0) {
2066
- return null;
2067
- }
2068
- const app = apps[0];
2069
- return app;
2070
- };
2071
- const getVersionedImplementationId = async (appKey) => {
2072
- const manifestEntry = getManifestEntry(appKey);
2073
- if (manifestEntry) {
2074
- return `${manifestEntry.implementationName}@${manifestEntry.version || "latest"}`;
2252
+ } catch {
2253
+ }
2075
2254
  }
2076
- const implementation = await getImplementation(appKey);
2077
- if (!implementation) return null;
2078
- return implementation.current_implementation_id;
2079
- };
2080
- return {
2081
- context: {
2082
- getVersionedImplementationId,
2083
- getManifestEntry,
2084
- getImplementation
2255
+ let manifestKey;
2256
+ if (existingEntry) {
2257
+ manifestKey = existingEntry[0];
2258
+ } else {
2259
+ manifestKey = await getPreferredManifestEntryKey({
2260
+ appKey,
2261
+ api
2262
+ });
2085
2263
  }
2264
+ manifest2.apps[manifestKey] = entry;
2265
+ await writeManifestToFile(manifest2, configPath);
2266
+ resolvedManifest = void 0;
2267
+ return [manifestKey, entry];
2086
2268
  };
2087
- };
2088
- var LockVersionSchema = zod.z.object({
2089
- appKey: zod.z.string().describe("The app key to lock version for (e.g., 'slack', 'gmail')")
2090
- });
2091
- var lockVersionPlugin = ({ sdk }) => {
2092
- const lockVersion = createFunction(
2093
- async function lockVersion2(options) {
2094
- const { appKey, configPath = ".zapierrc" } = options;
2095
- const resolvedPath = path.resolve(configPath);
2096
- const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2097
- const apps = [];
2098
- for await (const app2 of appsIterator) {
2099
- apps.push(app2);
2100
- break;
2101
- }
2102
- const app = apps[0];
2103
- const currentImplementationId = app.current_implementation_id;
2104
- const [implementationName, version] = currentImplementationId.split("@");
2105
- if (!implementationName || !version) {
2106
- throw new Error(
2107
- `Invalid implementation ID format: ${currentImplementationId}. Expected format: <implementationName>@<version>`
2108
- );
2109
- }
2110
- let config = { apps: {} };
2111
- if (fs.existsSync(resolvedPath)) {
2112
- try {
2113
- const configContent = fs.readFileSync(resolvedPath, "utf8");
2114
- config = JSON.parse(configContent);
2115
- if (!config.apps) {
2116
- config.apps = {};
2117
- }
2118
- } catch (error) {
2119
- console.warn(
2120
- `\u26A0\uFE0F Failed to parse existing config file, creating new one: ${error}`
2121
- );
2122
- config = { apps: {} };
2123
- }
2124
- }
2125
- config.apps[appKey] = {
2126
- implementationName,
2127
- version
2128
- };
2129
- fs.writeFileSync(resolvedPath, JSON.stringify(config, null, 2));
2130
- return {
2131
- data: {
2132
- ...app,
2133
- implementationName,
2134
- version
2135
- },
2136
- configPath: resolvedPath
2137
- };
2138
- },
2139
- LockVersionSchema.extend({
2140
- configPath: zod.z.string().optional().describe("Path to .zapierrc file (defaults to '.zapierrc')")
2141
- })
2142
- );
2143
2269
  return {
2144
- lockVersion,
2145
2270
  context: {
2146
- meta: {
2147
- lockVersion: {
2148
- categories: ["utility"],
2149
- inputSchema: LockVersionSchema
2150
- }
2151
- }
2271
+ getVersionedImplementationId,
2272
+ resolveAppKeys: async ({ appKeys }) => resolveAppKeys({
2273
+ appKeys,
2274
+ api,
2275
+ manifest: await getResolvedManifest() ?? { apps: {} }
2276
+ }),
2277
+ updateManifestEntry
2152
2278
  }
2153
2279
  };
2154
2280
  };
@@ -2277,52 +2403,162 @@ function createDebugFetch(options) {
2277
2403
  }
2278
2404
  };
2279
2405
  }
2280
-
2281
- // src/api/polling.ts
2406
+ var DEFAULT_TIMEOUT_MS = 18e4;
2407
+ var DEFAULT_SUCCESS_STATUS = 200;
2408
+ var DEFAULT_PENDING_STATUS = 202;
2409
+ var DEFAULT_INITIAL_DELAY_MS = 50;
2410
+ var DEFAULT_MAX_POLLING_INTERVAL_MS = 1e4;
2411
+ var MAX_CONSECUTIVE_ERRORS = 3;
2412
+ var MAX_TIMEOUT_BUFFER_MS = 1e4;
2413
+ var BASE_ERROR_BACKOFF_MS = 1e3;
2414
+ var JITTER_FACTOR = 0.5;
2415
+ var DEFAULT_POLLING_STAGES = [
2416
+ [125, 125],
2417
+ // Up to 125ms: poll every 125ms
2418
+ [375, 250],
2419
+ // Up to 375ms: poll every 250ms
2420
+ [875, 500],
2421
+ // Up to 875ms: poll every 500ms
2422
+ [1e4, 1e3],
2423
+ // Up to 10s: poll every 1s
2424
+ [3e4, 2500],
2425
+ // Up to 30s: poll every 2.5s
2426
+ [6e4, 5e3]
2427
+ // Up to 60s: poll every 5s
2428
+ ];
2429
+ var calculateWaitTime = (baseInterval, errorCount) => {
2430
+ const jitter = Math.random() * JITTER_FACTOR * baseInterval;
2431
+ const errorBackoff = Math.min(
2432
+ BASE_ERROR_BACKOFF_MS * (errorCount / 2),
2433
+ baseInterval * 2
2434
+ // Cap error backoff at 2x the base interval
2435
+ );
2436
+ return Math.floor(baseInterval + jitter + errorBackoff);
2437
+ };
2438
+ var processResponse = async (response, successStatus, pendingStatus, resultExtractor, errorCount) => {
2439
+ if (!response.ok) {
2440
+ return {
2441
+ status: "continue" /* Continue */,
2442
+ // If for some reason the status is pending, we don't want to increment the error count
2443
+ errorCount: response.status === pendingStatus ? errorCount : errorCount + 1
2444
+ };
2445
+ }
2446
+ if (response.status === successStatus) {
2447
+ try {
2448
+ const resultJson = await response.json();
2449
+ return {
2450
+ result: resultExtractor(resultJson),
2451
+ status: "success" /* Success */,
2452
+ errorCount: 0
2453
+ };
2454
+ } catch (error) {
2455
+ throw new ZapierApiError(
2456
+ "Result extractor failed to parse successful response as JSON",
2457
+ {
2458
+ statusCode: response.status,
2459
+ cause: error
2460
+ }
2461
+ );
2462
+ }
2463
+ }
2464
+ if (response.status !== pendingStatus) {
2465
+ throw new ZapierApiError(
2466
+ `Unexpected response status during polling: ${response.status}`,
2467
+ {
2468
+ statusCode: response.status
2469
+ }
2470
+ );
2471
+ }
2472
+ return {
2473
+ status: "continue" /* Continue */,
2474
+ errorCount: 0
2475
+ };
2476
+ };
2282
2477
  async function pollUntilComplete(options) {
2283
2478
  const {
2284
2479
  fetchPoll,
2285
- maxAttempts = 30,
2286
- initialDelay = 50,
2287
- maxDelay = 1e3,
2288
- successStatus = 200,
2289
- pendingStatus = 202,
2480
+ timeoutMs = DEFAULT_TIMEOUT_MS,
2481
+ initialDelay = DEFAULT_INITIAL_DELAY_MS,
2482
+ successStatus = DEFAULT_SUCCESS_STATUS,
2483
+ pendingStatus = DEFAULT_PENDING_STATUS,
2290
2484
  resultExtractor = (response) => response
2291
2485
  } = options;
2292
- let delay = initialDelay;
2486
+ if (timeoutMs <= 0) {
2487
+ throw new ZapierValidationError("Timeout must be greater than 0", {
2488
+ details: { timeoutMs }
2489
+ });
2490
+ }
2491
+ if (initialDelay < 0) {
2492
+ throw new ZapierValidationError("Initial delay must be non-negative", {
2493
+ details: { initialDelay }
2494
+ });
2495
+ }
2496
+ const startTime = Date.now();
2497
+ let attempts = 0;
2293
2498
  let errorCount = 0;
2294
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
2295
- const response = await fetchPoll();
2296
- if (response.status === successStatus) {
2297
- errorCount = 0;
2298
- const result = await response.json();
2299
- return resultExtractor(result);
2300
- } else if (response.status === pendingStatus) {
2301
- errorCount = 0;
2302
- if (attempt < maxAttempts - 1) {
2303
- await new Promise((resolve3) => setTimeout(resolve3, delay));
2304
- delay = Math.min(delay * 2, maxDelay);
2305
- continue;
2499
+ const pollingStages = [
2500
+ ...DEFAULT_POLLING_STAGES,
2501
+ [timeoutMs + MAX_TIMEOUT_BUFFER_MS, DEFAULT_MAX_POLLING_INTERVAL_MS]
2502
+ // Up to timeout + 10s: poll every 10s
2503
+ ];
2504
+ if (initialDelay > 0) {
2505
+ await promises.setTimeout(initialDelay);
2506
+ }
2507
+ while (true) {
2508
+ attempts++;
2509
+ const elapsedTime = Date.now() - startTime;
2510
+ const pollingInterval = pollingStages.find(
2511
+ ([maxTimeForStage, _interval]) => {
2512
+ return elapsedTime < maxTimeForStage;
2306
2513
  }
2307
- } else {
2308
- errorCount++;
2309
- if (errorCount >= 3) {
2514
+ );
2515
+ if (!pollingInterval) {
2516
+ throw new ZapierTimeoutError(
2517
+ `Operation timed out after ${Math.floor(elapsedTime / 1e3)}s (${attempts} attempts)`,
2518
+ {
2519
+ attempts
2520
+ }
2521
+ );
2522
+ }
2523
+ if (attempts > 1) {
2524
+ const waitTime = calculateWaitTime(pollingInterval[1], errorCount);
2525
+ await promises.setTimeout(waitTime);
2526
+ }
2527
+ try {
2528
+ const response = await fetchPoll();
2529
+ const {
2530
+ result,
2531
+ errorCount: newErrorCount,
2532
+ status
2533
+ } = await processResponse(
2534
+ response,
2535
+ successStatus,
2536
+ pendingStatus,
2537
+ resultExtractor,
2538
+ errorCount
2539
+ );
2540
+ errorCount = newErrorCount;
2541
+ if (status === "success" /* Success */) {
2542
+ return result;
2543
+ }
2544
+ if (errorCount >= MAX_CONSECUTIVE_ERRORS) {
2310
2545
  throw new ZapierApiError(
2311
2546
  `Poll request failed: ${response.status} ${response.statusText}`,
2312
2547
  { statusCode: response.status }
2313
2548
  );
2314
2549
  }
2315
- if (attempt < maxAttempts - 1) {
2316
- await new Promise((resolve3) => setTimeout(resolve3, delay));
2317
- delay = Math.min(delay * 2, maxDelay);
2318
- continue;
2550
+ } catch (error) {
2551
+ errorCount++;
2552
+ if (errorCount >= MAX_CONSECUTIVE_ERRORS) {
2553
+ throw new ZapierApiError(
2554
+ `Failed to poll after ${errorCount} consecutive errors: ${error instanceof Error ? error.message : String(error)}`,
2555
+ {
2556
+ cause: error
2557
+ }
2558
+ );
2319
2559
  }
2320
2560
  }
2321
2561
  }
2322
- throw new ZapierTimeoutError(
2323
- `Operation timed out after ${maxAttempts} attempts`,
2324
- { attempts: maxAttempts, maxAttempts }
2325
- );
2326
2562
  }
2327
2563
 
2328
2564
  // src/auth.ts
@@ -2377,9 +2613,8 @@ var ZapierApiClient = class {
2377
2613
  searchParams: options.searchParams,
2378
2614
  authRequired: options.authRequired
2379
2615
  }),
2380
- maxAttempts: options.maxAttempts,
2381
2616
  initialDelay: options.initialDelay,
2382
- maxDelay: options.maxDelay,
2617
+ timeoutMs: options.timeoutMs,
2383
2618
  successStatus: options.successStatus,
2384
2619
  pendingStatus: options.pendingStatus,
2385
2620
  resultExtractor: options.resultExtractor
@@ -3087,7 +3322,7 @@ function createSdk(options = {}, initialSdk = {}, initialContext = { meta: {} })
3087
3322
  };
3088
3323
  }
3089
3324
  function createZapierSdkWithoutRegistry(options = {}) {
3090
- return createSdk(options).addPlugin(apiPlugin).addPlugin(listAppsPlugin).addPlugin(manifestPlugin).addPlugin(getAppPlugin).addPlugin(listActionsPlugin).addPlugin(getActionPlugin).addPlugin(listInputFieldsPlugin).addPlugin(listInputFieldChoicesPlugin).addPlugin(runActionPlugin).addPlugin(lockVersionPlugin).addPlugin(listAuthenticationsPlugin).addPlugin(getAuthenticationPlugin).addPlugin(findFirstAuthenticationPlugin).addPlugin(findUniqueAuthenticationPlugin).addPlugin(requestPlugin).addPlugin(fetchPlugin).addPlugin(appsPlugin).addPlugin(getProfilePlugin);
3325
+ return createSdk(options).addPlugin(apiPlugin).addPlugin(manifestPlugin).addPlugin(listAppsPlugin).addPlugin(getAppPlugin).addPlugin(listActionsPlugin).addPlugin(getActionPlugin).addPlugin(listInputFieldsPlugin).addPlugin(listInputFieldChoicesPlugin).addPlugin(runActionPlugin).addPlugin(listAuthenticationsPlugin).addPlugin(getAuthenticationPlugin).addPlugin(findFirstAuthenticationPlugin).addPlugin(findUniqueAuthenticationPlugin).addPlugin(requestPlugin).addPlugin(fetchPlugin).addPlugin(appsPlugin).addPlugin(getProfilePlugin);
3091
3326
  }
3092
3327
  function createZapierSdk(options = {}) {
3093
3328
  return createZapierSdkWithoutRegistry(options).addPlugin(registryPlugin);
@@ -3097,6 +3332,7 @@ exports.ActionKeyPropertySchema = ActionKeyPropertySchema;
3097
3332
  exports.ActionTypePropertySchema = ActionTypePropertySchema;
3098
3333
  exports.AppKeyPropertySchema = AppKeyPropertySchema;
3099
3334
  exports.AuthenticationIdPropertySchema = AuthenticationIdPropertySchema;
3335
+ exports.DEFAULT_CONFIG_PATH = DEFAULT_CONFIG_PATH;
3100
3336
  exports.DebugPropertySchema = DebugPropertySchema;
3101
3337
  exports.InputsPropertySchema = InputsPropertySchema;
3102
3338
  exports.LimitPropertySchema = LimitPropertySchema;
@@ -3129,11 +3365,13 @@ exports.createZapierSdk = createZapierSdk;
3129
3365
  exports.createZapierSdkWithoutRegistry = createZapierSdkWithoutRegistry;
3130
3366
  exports.fetchPlugin = fetchPlugin;
3131
3367
  exports.findFirstAuthenticationPlugin = findFirstAuthenticationPlugin;
3368
+ exports.findManifestEntry = findManifestEntry;
3132
3369
  exports.findUniqueAuthenticationPlugin = findUniqueAuthenticationPlugin;
3133
3370
  exports.formatErrorMessage = formatErrorMessage;
3134
3371
  exports.getActionPlugin = getActionPlugin;
3135
3372
  exports.getAppPlugin = getAppPlugin;
3136
3373
  exports.getAuthenticationPlugin = getAuthenticationPlugin;
3374
+ exports.getPreferredManifestEntryKey = getPreferredManifestEntryKey;
3137
3375
  exports.getProfilePlugin = getProfilePlugin;
3138
3376
  exports.getResolutionOrder = getResolutionOrder;
3139
3377
  exports.getResolutionOrderForParams = getResolutionOrderForParams;
@@ -3150,9 +3388,8 @@ exports.listActionsPlugin = listActionsPlugin;
3150
3388
  exports.listAppsPlugin = listAppsPlugin;
3151
3389
  exports.listAuthenticationsPlugin = listAuthenticationsPlugin;
3152
3390
  exports.listInputFieldsPlugin = listInputFieldsPlugin;
3153
- exports.loadManifestFromFile = loadManifestFromFile;
3154
- exports.lockVersionPlugin = lockVersionPlugin;
3155
3391
  exports.manifestPlugin = manifestPlugin;
3392
+ exports.readManifestFromFile = readManifestFromFile;
3156
3393
  exports.registryPlugin = registryPlugin;
3157
3394
  exports.requestPlugin = requestPlugin;
3158
3395
  exports.resolverRegistry = resolverRegistry;