@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.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { readFileSync, existsSync, writeFileSync } from 'fs';
3
- import { resolve } from 'path';
2
+ import { setTimeout } from 'timers/promises';
4
3
 
5
4
  // src/types/properties.ts
6
5
  function withFormatter(schema, formatMeta) {
@@ -651,16 +650,6 @@ function splitVersionedKey(versionedKey) {
651
650
  }
652
651
  return [versionedKey, void 0];
653
652
  }
654
- function normalizeImplementationToAppItem(implementation) {
655
- const [selectedApi, appVersion] = implementation.selected_api ? splitVersionedKey(implementation.selected_api) : [implementation.selected_api || "", void 0];
656
- return {
657
- title: implementation.name || selectedApi,
658
- key: selectedApi,
659
- current_implementation_id: implementation.selected_api || "",
660
- version: appVersion
661
- // Extract version separately
662
- };
663
- }
664
653
  function normalizeImplementationMetaToAppItem(implementationMeta) {
665
654
  const [selectedApi, appVersion] = splitVersionedKey(implementationMeta.id);
666
655
  return {
@@ -722,50 +711,8 @@ function normalizeActionItem(action) {
722
711
  type: "action"
723
712
  };
724
713
  }
725
- function groupVersionedAppKeysByType(appKeys) {
726
- const result = {
727
- selectedApi: [],
728
- slug: []
729
- };
730
- const seenSelectedApi = /* @__PURE__ */ new Set();
731
- const seenSlugs = /* @__PURE__ */ new Set();
732
- for (const key of appKeys) {
733
- const [keyWithoutVersion, version] = splitVersionedKey(key);
734
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
735
- if (uuidRegex.test(keyWithoutVersion)) {
736
- throw new Error(
737
- `UUID app keys are not supported. Use app slug or implementation ID instead of: ${key}`
738
- );
739
- }
740
- if (isSnakeCasedSlug(keyWithoutVersion)) {
741
- const dashified = dashifySnakeCasedSlug(keyWithoutVersion);
742
- const slugWithVersion = version ? `${dashified}@${version}` : dashified;
743
- if (!seenSlugs.has(slugWithVersion)) {
744
- seenSlugs.add(slugWithVersion);
745
- result.slug.push(slugWithVersion);
746
- }
747
- continue;
748
- }
749
- if (keyWithoutVersion.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)) {
750
- seenSlugs.add(key);
751
- result.slug.push(key);
752
- continue;
753
- }
754
- if (!seenSelectedApi.has(key)) {
755
- seenSelectedApi.add(key);
756
- result.selectedApi.push(key);
757
- }
758
- }
759
- return result;
760
- }
761
- function groupAppKeysByType(appKeys) {
762
- const grouped = groupVersionedAppKeysByType(appKeys);
763
- return {
764
- selectedApi: [
765
- ...new Set(grouped.selectedApi.map((key) => key.split("@")[0]))
766
- ],
767
- slug: [...new Set(grouped.slug.map((key) => key.split("@")[0]))]
768
- };
714
+ function isSlug(slug) {
715
+ return !!slug.match(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
769
716
  }
770
717
  function isSnakeCasedSlug(slug) {
771
718
  if (slug.match(/^_[0-9]/)) {
@@ -782,15 +729,54 @@ function dashifySnakeCasedSlug(slug) {
782
729
  }
783
730
  return slug.replace(/_/g, "-");
784
731
  }
732
+ function isUuid(appKey) {
733
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
734
+ appKey
735
+ );
736
+ }
737
+ function toAppLocator(appKey) {
738
+ const [appKeyWithoutVersion, version] = splitVersionedKey(appKey);
739
+ if (isUuid(appKeyWithoutVersion)) {
740
+ throw new Error(
741
+ `UUID app keys are not supported. Use app slug or implementation ID instead of: ${appKey}`
742
+ );
743
+ }
744
+ const slug = isSlug(appKeyWithoutVersion) ? appKeyWithoutVersion : isSnakeCasedSlug(appKeyWithoutVersion) ? dashifySnakeCasedSlug(appKeyWithoutVersion) : void 0;
745
+ return {
746
+ lookupAppKey: appKeyWithoutVersion,
747
+ slug,
748
+ implementationName: slug ? void 0 : appKeyWithoutVersion,
749
+ version
750
+ };
751
+ }
752
+ function isResolvedAppLocator(appLocator) {
753
+ return !!appLocator.implementationName;
754
+ }
755
+ function toImplementationId(appLocator) {
756
+ return `${appLocator.implementationName}@${appLocator.version || "latest"}`;
757
+ }
785
758
 
786
759
  // src/plugins/listApps/index.ts
787
760
  var listAppsPlugin = ({ context }) => {
788
761
  const listApps = createPaginatedFunction(async function listAppsPage(options) {
789
762
  const api = context.api;
790
763
  const opts = options;
791
- const appKeys = [...opts.appKeys ?? []].map(
792
- (key) => splitVersionedKey(key)[0]
793
- );
764
+ const appLocators = await context.resolveAppKeys({
765
+ appKeys: [...opts.appKeys ?? []]
766
+ });
767
+ const implementationNameToLocator = {};
768
+ for (const locator of appLocators) {
769
+ implementationNameToLocator[locator.implementationName] = [
770
+ ...implementationNameToLocator[locator.implementationName] ?? [],
771
+ locator
772
+ ];
773
+ }
774
+ const duplicatedLookupAppKeys = Object.keys(implementationNameToLocator).filter((key) => implementationNameToLocator[key].length > 1).map((key) => implementationNameToLocator[key]).flat().map((locator) => locator.lookupAppKey);
775
+ if (duplicatedLookupAppKeys.length > 0) {
776
+ throw new Error(
777
+ `Duplicate lookup app keys found: ${duplicatedLookupAppKeys.join(", ")}`
778
+ );
779
+ }
794
780
  if (opts.search) {
795
781
  const searchParams2 = {};
796
782
  searchParams2.term = opts.search;
@@ -803,11 +789,17 @@ var listAppsPlugin = ({ context }) => {
803
789
  const implementations = searchEnvelope.results.map(
804
790
  normalizeImplementationMetaToAppItem
805
791
  );
806
- const appKeysSet = new Set(appKeys);
792
+ const implementationNameSet = new Set(
793
+ appLocators.map((locator) => locator.implementationName)
794
+ );
807
795
  for (const implementation of implementations) {
808
- if (!appKeysSet.has(implementation.key)) {
809
- appKeysSet.add(implementation.key);
810
- appKeys.push(implementation.key);
796
+ const [implementationName] = splitVersionedKey(implementation.key);
797
+ if (!implementationNameSet.has(implementationName)) {
798
+ implementationNameSet.add(implementationName);
799
+ appLocators.push({
800
+ ...toAppLocator(implementation.key),
801
+ implementationName
802
+ });
811
803
  }
812
804
  }
813
805
  }
@@ -815,19 +807,13 @@ var listAppsPlugin = ({ context }) => {
815
807
  if (opts.pageSize) {
816
808
  searchParams.limit = opts.pageSize.toString();
817
809
  }
818
- searchParams.latest_only = "true";
810
+ if (appLocators.length === 0) {
811
+ searchParams.latest_only = "true";
812
+ }
819
813
  if (opts.cursor) {
820
814
  searchParams.offset = opts.cursor;
821
815
  }
822
- if (appKeys.length > 0) {
823
- const groupedAppKeys = groupAppKeysByType(appKeys);
824
- if (groupedAppKeys.selectedApi.length > 0) {
825
- searchParams.selected_apis = groupedAppKeys.selectedApi.join(",");
826
- }
827
- if (groupedAppKeys.slug.length > 0) {
828
- searchParams.slugs = groupedAppKeys.slug.join(",");
829
- }
830
- }
816
+ searchParams.selected_apis = appLocators.map((locator) => toImplementationId(locator)).join(",");
831
817
  const implementationsEnvelope = await api.get(
832
818
  "/api/v4/implementations-meta/lookup/",
833
819
  {
@@ -1474,6 +1460,7 @@ var ListAuthenticationsSchema = z.object({
1474
1460
  appKey: AppKeyPropertySchema.optional().describe(
1475
1461
  "App key of authentications to list (e.g., 'SlackCLIAPI')"
1476
1462
  ),
1463
+ authenticationIds: z.array(z.string()).optional().describe("List of authentication IDs to filter by"),
1477
1464
  search: z.string().optional().describe("Search term to filter authentications by title"),
1478
1465
  title: z.string().optional().describe("Filter authentications by exact title match"),
1479
1466
  accountId: z.string().optional().describe("Filter by account ID"),
@@ -1497,6 +1484,9 @@ var listAuthenticationsPlugin = ({ context }) => {
1497
1484
  searchParams.versionless_selected_api = versionlessSelectedApi;
1498
1485
  }
1499
1486
  }
1487
+ if (options.authenticationIds && options.authenticationIds.length > 0) {
1488
+ searchParams.ids = options.authenticationIds.join(",");
1489
+ }
1500
1490
  if (options.search) {
1501
1491
  searchParams.search = options.search;
1502
1492
  } else if (options.title) {
@@ -1569,17 +1559,17 @@ var GetAppSchema = withOutputSchema(
1569
1559
  );
1570
1560
 
1571
1561
  // src/plugins/getApp/index.ts
1572
- var getAppPlugin = ({ context }) => {
1562
+ var getAppPlugin = ({ sdk }) => {
1573
1563
  const getApp = createFunction(async function getApp2(options) {
1574
- const app = await context.getImplementation(options.appKey);
1575
- if (!app) {
1576
- throw new ZapierAppNotFoundError("App not found", {
1577
- appKey: options.appKey
1578
- });
1564
+ const appsIterator = sdk.listApps({ appKeys: [options.appKey] }).items();
1565
+ for await (const app of appsIterator) {
1566
+ return {
1567
+ data: app
1568
+ };
1579
1569
  }
1580
- return {
1581
- data: app
1582
- };
1570
+ throw new ZapierAppNotFoundError("App not found", {
1571
+ appKey: options.appKey
1572
+ });
1583
1573
  }, GetAppSchema);
1584
1574
  return {
1585
1575
  getApp,
@@ -1945,6 +1935,67 @@ var requestPlugin = ({ context }) => {
1945
1935
  }
1946
1936
  };
1947
1937
  };
1938
+
1939
+ // src/utils/file-utils.ts
1940
+ var inMemoryFiles = {};
1941
+ var fsPromises = null;
1942
+ var pathModule = null;
1943
+ async function loadFsPromises() {
1944
+ if (fsPromises) return fsPromises;
1945
+ try {
1946
+ fsPromises = await import('fs/promises');
1947
+ return fsPromises;
1948
+ } catch {
1949
+ return null;
1950
+ }
1951
+ }
1952
+ async function loadPathModule() {
1953
+ if (pathModule) return pathModule;
1954
+ try {
1955
+ pathModule = await import('path');
1956
+ return pathModule;
1957
+ } catch {
1958
+ return null;
1959
+ }
1960
+ }
1961
+ async function resolve(path, basePath = "/") {
1962
+ const pathModule2 = await loadPathModule();
1963
+ if (pathModule2) {
1964
+ return pathModule2.resolve(path);
1965
+ }
1966
+ if (path.startsWith("/")) {
1967
+ return path;
1968
+ }
1969
+ if (path.startsWith("./")) {
1970
+ const cleanPath = path.slice(2);
1971
+ return basePath.endsWith("/") ? basePath + cleanPath : basePath + "/" + cleanPath;
1972
+ }
1973
+ if (path.startsWith("../")) {
1974
+ const cleanPath = path.replace(/^(\.\.\/)+/, "");
1975
+ return basePath.endsWith("/") ? basePath + cleanPath : basePath + "/" + cleanPath;
1976
+ }
1977
+ return basePath.endsWith("/") ? basePath + path : basePath + "/" + path;
1978
+ }
1979
+ async function writeFile(filePath, content) {
1980
+ const fs = await loadFsPromises();
1981
+ if (fs) {
1982
+ await fs.writeFile(filePath, content, "utf8");
1983
+ return;
1984
+ }
1985
+ inMemoryFiles[filePath] = content;
1986
+ }
1987
+ async function readFile(filePath) {
1988
+ const fs = await loadFsPromises();
1989
+ if (fs) {
1990
+ return await fs.readFile(filePath, "utf8");
1991
+ }
1992
+ const content = inMemoryFiles[filePath];
1993
+ if (content !== void 0) {
1994
+ return content;
1995
+ }
1996
+ throw new Error(`File not found: ${filePath}`);
1997
+ }
1998
+ var DEFAULT_CONFIG_PATH = ".zapierrc";
1948
1999
  var ManifestSchema = z.object({
1949
2000
  apps: z.record(
1950
2001
  z.string(),
@@ -1967,6 +2018,15 @@ z.object({
1967
2018
  ).optional().describe("Direct manifest object")
1968
2019
  });
1969
2020
 
2021
+ // src/utils/array-utils.ts
2022
+ async function toArrayFromAsync(asyncIterable) {
2023
+ const result = [];
2024
+ for await (const item of asyncIterable) {
2025
+ result.push(item);
2026
+ }
2027
+ return result;
2028
+ }
2029
+
1970
2030
  // src/plugins/manifest/index.ts
1971
2031
  function parseManifestContent(content, source) {
1972
2032
  try {
@@ -1984,169 +2044,235 @@ function parseManifestContent(content, source) {
1984
2044
  return null;
1985
2045
  }
1986
2046
  }
1987
- function loadManifestFromFile(filePath) {
2047
+ async function readManifestFromFile(filePath) {
1988
2048
  try {
1989
- const resolvedPath = resolve(filePath);
1990
- const content = readFileSync(resolvedPath, "utf8");
2049
+ const resolvedPath = await resolve(filePath);
2050
+ const content = await readFile(resolvedPath);
1991
2051
  return parseManifestContent(content, resolvedPath);
1992
2052
  } catch {
1993
- console.warn(`\u26A0\uFE0F Failed to load manifest from ${filePath}`);
2053
+ console.warn(`\u26A0\uFE0F Failed to read manifest from ${filePath}`);
1994
2054
  return null;
1995
2055
  }
1996
2056
  }
1997
- var emitWarning = (appKey) => {
1998
- console.warn(
1999
- `
2000
- ${"\u26A0\uFE0F".padEnd(3)} ${"WARNING".padEnd(8)} No manifest version found for '${appKey}'`
2001
- );
2002
- console.warn(
2003
- ` ${"\u21B3".padEnd(3)} Using a manifest ensures version locking and prevents unexpected behavior due to version changes.`
2057
+ async function writeManifestToFile(manifest, filePath) {
2058
+ const resolvedPath = await resolve(filePath);
2059
+ await writeFile(resolvedPath, JSON.stringify(manifest, null, 2));
2060
+ }
2061
+ async function getPreferredManifestEntryKey({
2062
+ appKey,
2063
+ api
2064
+ }) {
2065
+ const locator = toAppLocator(appKey);
2066
+ if (locator.slug) {
2067
+ return locator.slug;
2068
+ }
2069
+ if (locator.implementationName) {
2070
+ try {
2071
+ const implementationsEnvelope = await api.get(`/api/v4/implementations-meta/lookup/`, {
2072
+ searchParams: {
2073
+ selected_apis: locator.implementationName
2074
+ }
2075
+ });
2076
+ if (implementationsEnvelope.results.length > 0 && implementationsEnvelope.results[0].slug) {
2077
+ return implementationsEnvelope.results[0].slug;
2078
+ }
2079
+ } catch {
2080
+ }
2081
+ return locator.implementationName;
2082
+ }
2083
+ return locator.lookupAppKey;
2084
+ }
2085
+ async function listAppsForSlugsPage({
2086
+ slugs,
2087
+ cursor,
2088
+ api
2089
+ }) {
2090
+ const searchParams = {};
2091
+ if (slugs.length > 0) {
2092
+ searchParams.slugs = slugs.join(",");
2093
+ }
2094
+ if (cursor) {
2095
+ searchParams.offset = cursor;
2096
+ }
2097
+ const implementationsEnvelope = await api.get(
2098
+ "/api/v4/implementations-meta/lookup/",
2099
+ {
2100
+ searchParams
2101
+ }
2004
2102
  );
2005
- console.warn(
2006
- ` ${"\u21B3".padEnd(3)} Generate/update the manifest with: \`zapier-sdk lock-version ${appKey}\`
2007
- `
2103
+ return {
2104
+ data: implementationsEnvelope.results.map(
2105
+ normalizeImplementationMetaToAppItem
2106
+ ),
2107
+ nextCursor: extractCursor(implementationsEnvelope)
2108
+ };
2109
+ }
2110
+ function findManifestEntry({
2111
+ appKey,
2112
+ manifest
2113
+ }) {
2114
+ const [appKeyWithoutVersion] = splitVersionedKey(appKey);
2115
+ if (manifest.apps[appKeyWithoutVersion]) {
2116
+ return [appKeyWithoutVersion, manifest.apps[appKeyWithoutVersion]];
2117
+ }
2118
+ if (isSnakeCasedSlug(appKey)) {
2119
+ const slug = dashifySnakeCasedSlug(appKey);
2120
+ if (manifest.apps[slug]) {
2121
+ return [slug, manifest.apps[slug]];
2122
+ }
2123
+ }
2124
+ for (const [key, entry] of Object.entries(manifest.apps)) {
2125
+ if (entry.implementationName === appKeyWithoutVersion) {
2126
+ return [key, entry];
2127
+ }
2128
+ }
2129
+ return null;
2130
+ }
2131
+ async function resolveAppKeys({
2132
+ appKeys,
2133
+ api,
2134
+ manifest
2135
+ }) {
2136
+ const locators = appKeys.map(toAppLocator);
2137
+ const locatorsWithManifest = locators.map((locator) => {
2138
+ const manifestEntryResult = findManifestEntry({
2139
+ appKey: locator.lookupAppKey,
2140
+ manifest
2141
+ });
2142
+ if (manifestEntryResult) {
2143
+ const [, manifestEntry] = manifestEntryResult;
2144
+ const resolvedVersion = locator.version || manifestEntry.version;
2145
+ const resolvedLocator = {
2146
+ ...locator,
2147
+ implementationName: manifestEntry.implementationName,
2148
+ version: resolvedVersion
2149
+ };
2150
+ return resolvedLocator;
2151
+ }
2152
+ return locator;
2153
+ });
2154
+ const unresolvedLocators = locatorsWithManifest.filter(
2155
+ (locator) => !isResolvedAppLocator(locator)
2008
2156
  );
2009
- };
2157
+ const slugsToResolve = unresolvedLocators.map((locator) => locator.slug).filter((slug) => !!slug).filter((slug, index, array) => array.indexOf(slug) === index);
2158
+ if (slugsToResolve.length === 0) {
2159
+ return locatorsWithManifest.filter(isResolvedAppLocator);
2160
+ }
2161
+ const iterator = paginate(listAppsForSlugsPage, {
2162
+ slugs: slugsToResolve,
2163
+ api
2164
+ });
2165
+ const pages = await toArrayFromAsync(iterator);
2166
+ const apps = pages.flatMap((page) => page.data);
2167
+ const slugToAppData = /* @__PURE__ */ new Map();
2168
+ for (const app of apps) {
2169
+ if (app.slug) {
2170
+ slugToAppData.set(app.slug, app);
2171
+ }
2172
+ }
2173
+ const slugResolvedLocators = locatorsWithManifest.map((locator) => {
2174
+ if (isResolvedAppLocator(locator)) {
2175
+ return locator;
2176
+ }
2177
+ if (locator.slug) {
2178
+ const appData = slugToAppData.get(locator.slug);
2179
+ if (appData) {
2180
+ const manifestEntryByImplementationName = findManifestEntry({
2181
+ appKey: appData.key,
2182
+ // appData.key is the implementation name
2183
+ manifest
2184
+ });
2185
+ let version = locator.version;
2186
+ if (!version) {
2187
+ version = manifestEntryByImplementationName ? manifestEntryByImplementationName[1].version || appData.version : appData.version;
2188
+ }
2189
+ return {
2190
+ ...locator,
2191
+ implementationName: appData.key,
2192
+ version
2193
+ };
2194
+ }
2195
+ }
2196
+ return locator;
2197
+ });
2198
+ return slugResolvedLocators.filter(isResolvedAppLocator);
2199
+ }
2010
2200
  var manifestPlugin = (params) => {
2011
- const { sdk, context } = params;
2201
+ const { context } = params;
2012
2202
  const { api, options } = context;
2013
- const { manifestPath = ".zapierrc", manifest } = options || {};
2203
+ const { manifestPath = DEFAULT_CONFIG_PATH, manifest } = options || {};
2014
2204
  let resolvedManifest;
2015
- function resolveManifest() {
2205
+ async function resolveManifest() {
2016
2206
  if (manifest) {
2017
2207
  return manifest;
2018
2208
  }
2019
2209
  if (manifestPath) {
2020
- return loadManifestFromFile(manifestPath);
2210
+ return await readManifestFromFile(manifestPath);
2021
2211
  }
2022
2212
  return null;
2023
2213
  }
2024
- const getResolvedManifest = () => {
2214
+ const getResolvedManifest = async () => {
2025
2215
  if (typeof resolvedManifest === "undefined") {
2026
- resolvedManifest = resolveManifest() ?? null;
2216
+ resolvedManifest = await resolveManifest() ?? null;
2027
2217
  }
2028
2218
  return resolvedManifest;
2029
2219
  };
2030
- const getManifestEntry = (appKey) => {
2031
- return getResolvedManifest()?.apps?.[appKey] || null;
2220
+ const getVersionedImplementationId = async (appKey) => {
2221
+ const resolvedApps = await resolveAppKeys({
2222
+ appKeys: [appKey],
2223
+ api,
2224
+ manifest: await getResolvedManifest() ?? { apps: {} }
2225
+ });
2226
+ const resolvedApp = resolvedApps[0];
2227
+ if (!resolvedApp) return null;
2228
+ return `${resolvedApp.implementationName}@${resolvedApp.version || "latest"}`;
2032
2229
  };
2033
- const getImplementation = async (appKey) => {
2034
- let selectedApi = null;
2035
- const manifestImplementation = getResolvedManifest()?.apps?.[appKey];
2036
- const [versionlessAppKey, version] = splitVersionedKey(appKey);
2037
- if (version) {
2038
- selectedApi = `${versionlessAppKey}@${version}`;
2039
- } else if (manifestImplementation) {
2040
- selectedApi = `${manifestImplementation.implementationName}@${manifestImplementation.version || "latest"}`;
2041
- }
2042
- if (selectedApi) {
2043
- const searchParams = {
2044
- selected_apis: selectedApi
2045
- };
2046
- const implementationData = await api.get(
2047
- "/api/v4/implementations/",
2048
- {
2049
- searchParams
2230
+ const updateManifestEntry = async (appKey, entry, configPath = DEFAULT_CONFIG_PATH) => {
2231
+ const manifest2 = await readManifestFromFile(configPath) || { apps: {} };
2232
+ let existingEntry = findManifestEntry({
2233
+ appKey,
2234
+ manifest: manifest2
2235
+ });
2236
+ if (!existingEntry) {
2237
+ try {
2238
+ const resolvedApps = await resolveAppKeys({
2239
+ appKeys: [appKey],
2240
+ api,
2241
+ manifest: manifest2
2242
+ });
2243
+ if (resolvedApps.length > 0) {
2244
+ const resolvedImplementationName = resolvedApps[0].implementationName;
2245
+ existingEntry = findManifestEntry({
2246
+ appKey: resolvedImplementationName,
2247
+ manifest: manifest2
2248
+ });
2050
2249
  }
2051
- );
2052
- const implementationResults = implementationData.results[0];
2053
- if (!implementationResults) return null;
2054
- return normalizeImplementationToAppItem(implementationResults);
2055
- }
2056
- emitWarning(appKey);
2057
- const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2058
- const apps = [];
2059
- for await (const app2 of appsIterator) {
2060
- apps.push(app2);
2061
- break;
2062
- }
2063
- if (apps.length === 0) {
2064
- return null;
2065
- }
2066
- const app = apps[0];
2067
- return app;
2068
- };
2069
- const getVersionedImplementationId = async (appKey) => {
2070
- const manifestEntry = getManifestEntry(appKey);
2071
- if (manifestEntry) {
2072
- return `${manifestEntry.implementationName}@${manifestEntry.version || "latest"}`;
2250
+ } catch {
2251
+ }
2073
2252
  }
2074
- const implementation = await getImplementation(appKey);
2075
- if (!implementation) return null;
2076
- return implementation.current_implementation_id;
2077
- };
2078
- return {
2079
- context: {
2080
- getVersionedImplementationId,
2081
- getManifestEntry,
2082
- getImplementation
2253
+ let manifestKey;
2254
+ if (existingEntry) {
2255
+ manifestKey = existingEntry[0];
2256
+ } else {
2257
+ manifestKey = await getPreferredManifestEntryKey({
2258
+ appKey,
2259
+ api
2260
+ });
2083
2261
  }
2262
+ manifest2.apps[manifestKey] = entry;
2263
+ await writeManifestToFile(manifest2, configPath);
2264
+ resolvedManifest = void 0;
2265
+ return [manifestKey, entry];
2084
2266
  };
2085
- };
2086
- var LockVersionSchema = z.object({
2087
- appKey: z.string().describe("The app key to lock version for (e.g., 'slack', 'gmail')")
2088
- });
2089
- var lockVersionPlugin = ({ sdk }) => {
2090
- const lockVersion = createFunction(
2091
- async function lockVersion2(options) {
2092
- const { appKey, configPath = ".zapierrc" } = options;
2093
- const resolvedPath = resolve(configPath);
2094
- const appsIterator = sdk.listApps({ appKeys: [appKey] }).items();
2095
- const apps = [];
2096
- for await (const app2 of appsIterator) {
2097
- apps.push(app2);
2098
- break;
2099
- }
2100
- const app = apps[0];
2101
- const currentImplementationId = app.current_implementation_id;
2102
- const [implementationName, version] = currentImplementationId.split("@");
2103
- if (!implementationName || !version) {
2104
- throw new Error(
2105
- `Invalid implementation ID format: ${currentImplementationId}. Expected format: <implementationName>@<version>`
2106
- );
2107
- }
2108
- let config = { apps: {} };
2109
- if (existsSync(resolvedPath)) {
2110
- try {
2111
- const configContent = readFileSync(resolvedPath, "utf8");
2112
- config = JSON.parse(configContent);
2113
- if (!config.apps) {
2114
- config.apps = {};
2115
- }
2116
- } catch (error) {
2117
- console.warn(
2118
- `\u26A0\uFE0F Failed to parse existing config file, creating new one: ${error}`
2119
- );
2120
- config = { apps: {} };
2121
- }
2122
- }
2123
- config.apps[appKey] = {
2124
- implementationName,
2125
- version
2126
- };
2127
- writeFileSync(resolvedPath, JSON.stringify(config, null, 2));
2128
- return {
2129
- data: {
2130
- ...app,
2131
- implementationName,
2132
- version
2133
- },
2134
- configPath: resolvedPath
2135
- };
2136
- },
2137
- LockVersionSchema.extend({
2138
- configPath: z.string().optional().describe("Path to .zapierrc file (defaults to '.zapierrc')")
2139
- })
2140
- );
2141
2267
  return {
2142
- lockVersion,
2143
2268
  context: {
2144
- meta: {
2145
- lockVersion: {
2146
- categories: ["utility"],
2147
- inputSchema: LockVersionSchema
2148
- }
2149
- }
2269
+ getVersionedImplementationId,
2270
+ resolveAppKeys: async ({ appKeys }) => resolveAppKeys({
2271
+ appKeys,
2272
+ api,
2273
+ manifest: await getResolvedManifest() ?? { apps: {} }
2274
+ }),
2275
+ updateManifestEntry
2150
2276
  }
2151
2277
  };
2152
2278
  };
@@ -2275,52 +2401,162 @@ function createDebugFetch(options) {
2275
2401
  }
2276
2402
  };
2277
2403
  }
2278
-
2279
- // src/api/polling.ts
2404
+ var DEFAULT_TIMEOUT_MS = 18e4;
2405
+ var DEFAULT_SUCCESS_STATUS = 200;
2406
+ var DEFAULT_PENDING_STATUS = 202;
2407
+ var DEFAULT_INITIAL_DELAY_MS = 50;
2408
+ var DEFAULT_MAX_POLLING_INTERVAL_MS = 1e4;
2409
+ var MAX_CONSECUTIVE_ERRORS = 3;
2410
+ var MAX_TIMEOUT_BUFFER_MS = 1e4;
2411
+ var BASE_ERROR_BACKOFF_MS = 1e3;
2412
+ var JITTER_FACTOR = 0.5;
2413
+ var DEFAULT_POLLING_STAGES = [
2414
+ [125, 125],
2415
+ // Up to 125ms: poll every 125ms
2416
+ [375, 250],
2417
+ // Up to 375ms: poll every 250ms
2418
+ [875, 500],
2419
+ // Up to 875ms: poll every 500ms
2420
+ [1e4, 1e3],
2421
+ // Up to 10s: poll every 1s
2422
+ [3e4, 2500],
2423
+ // Up to 30s: poll every 2.5s
2424
+ [6e4, 5e3]
2425
+ // Up to 60s: poll every 5s
2426
+ ];
2427
+ var calculateWaitTime = (baseInterval, errorCount) => {
2428
+ const jitter = Math.random() * JITTER_FACTOR * baseInterval;
2429
+ const errorBackoff = Math.min(
2430
+ BASE_ERROR_BACKOFF_MS * (errorCount / 2),
2431
+ baseInterval * 2
2432
+ // Cap error backoff at 2x the base interval
2433
+ );
2434
+ return Math.floor(baseInterval + jitter + errorBackoff);
2435
+ };
2436
+ var processResponse = async (response, successStatus, pendingStatus, resultExtractor, errorCount) => {
2437
+ if (!response.ok) {
2438
+ return {
2439
+ status: "continue" /* Continue */,
2440
+ // If for some reason the status is pending, we don't want to increment the error count
2441
+ errorCount: response.status === pendingStatus ? errorCount : errorCount + 1
2442
+ };
2443
+ }
2444
+ if (response.status === successStatus) {
2445
+ try {
2446
+ const resultJson = await response.json();
2447
+ return {
2448
+ result: resultExtractor(resultJson),
2449
+ status: "success" /* Success */,
2450
+ errorCount: 0
2451
+ };
2452
+ } catch (error) {
2453
+ throw new ZapierApiError(
2454
+ "Result extractor failed to parse successful response as JSON",
2455
+ {
2456
+ statusCode: response.status,
2457
+ cause: error
2458
+ }
2459
+ );
2460
+ }
2461
+ }
2462
+ if (response.status !== pendingStatus) {
2463
+ throw new ZapierApiError(
2464
+ `Unexpected response status during polling: ${response.status}`,
2465
+ {
2466
+ statusCode: response.status
2467
+ }
2468
+ );
2469
+ }
2470
+ return {
2471
+ status: "continue" /* Continue */,
2472
+ errorCount: 0
2473
+ };
2474
+ };
2280
2475
  async function pollUntilComplete(options) {
2281
2476
  const {
2282
2477
  fetchPoll,
2283
- maxAttempts = 30,
2284
- initialDelay = 50,
2285
- maxDelay = 1e3,
2286
- successStatus = 200,
2287
- pendingStatus = 202,
2478
+ timeoutMs = DEFAULT_TIMEOUT_MS,
2479
+ initialDelay = DEFAULT_INITIAL_DELAY_MS,
2480
+ successStatus = DEFAULT_SUCCESS_STATUS,
2481
+ pendingStatus = DEFAULT_PENDING_STATUS,
2288
2482
  resultExtractor = (response) => response
2289
2483
  } = options;
2290
- let delay = initialDelay;
2484
+ if (timeoutMs <= 0) {
2485
+ throw new ZapierValidationError("Timeout must be greater than 0", {
2486
+ details: { timeoutMs }
2487
+ });
2488
+ }
2489
+ if (initialDelay < 0) {
2490
+ throw new ZapierValidationError("Initial delay must be non-negative", {
2491
+ details: { initialDelay }
2492
+ });
2493
+ }
2494
+ const startTime = Date.now();
2495
+ let attempts = 0;
2291
2496
  let errorCount = 0;
2292
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
2293
- const response = await fetchPoll();
2294
- if (response.status === successStatus) {
2295
- errorCount = 0;
2296
- const result = await response.json();
2297
- return resultExtractor(result);
2298
- } else if (response.status === pendingStatus) {
2299
- errorCount = 0;
2300
- if (attempt < maxAttempts - 1) {
2301
- await new Promise((resolve3) => setTimeout(resolve3, delay));
2302
- delay = Math.min(delay * 2, maxDelay);
2303
- continue;
2497
+ const pollingStages = [
2498
+ ...DEFAULT_POLLING_STAGES,
2499
+ [timeoutMs + MAX_TIMEOUT_BUFFER_MS, DEFAULT_MAX_POLLING_INTERVAL_MS]
2500
+ // Up to timeout + 10s: poll every 10s
2501
+ ];
2502
+ if (initialDelay > 0) {
2503
+ await setTimeout(initialDelay);
2504
+ }
2505
+ while (true) {
2506
+ attempts++;
2507
+ const elapsedTime = Date.now() - startTime;
2508
+ const pollingInterval = pollingStages.find(
2509
+ ([maxTimeForStage, _interval]) => {
2510
+ return elapsedTime < maxTimeForStage;
2304
2511
  }
2305
- } else {
2306
- errorCount++;
2307
- if (errorCount >= 3) {
2512
+ );
2513
+ if (!pollingInterval) {
2514
+ throw new ZapierTimeoutError(
2515
+ `Operation timed out after ${Math.floor(elapsedTime / 1e3)}s (${attempts} attempts)`,
2516
+ {
2517
+ attempts
2518
+ }
2519
+ );
2520
+ }
2521
+ if (attempts > 1) {
2522
+ const waitTime = calculateWaitTime(pollingInterval[1], errorCount);
2523
+ await setTimeout(waitTime);
2524
+ }
2525
+ try {
2526
+ const response = await fetchPoll();
2527
+ const {
2528
+ result,
2529
+ errorCount: newErrorCount,
2530
+ status
2531
+ } = await processResponse(
2532
+ response,
2533
+ successStatus,
2534
+ pendingStatus,
2535
+ resultExtractor,
2536
+ errorCount
2537
+ );
2538
+ errorCount = newErrorCount;
2539
+ if (status === "success" /* Success */) {
2540
+ return result;
2541
+ }
2542
+ if (errorCount >= MAX_CONSECUTIVE_ERRORS) {
2308
2543
  throw new ZapierApiError(
2309
2544
  `Poll request failed: ${response.status} ${response.statusText}`,
2310
2545
  { statusCode: response.status }
2311
2546
  );
2312
2547
  }
2313
- if (attempt < maxAttempts - 1) {
2314
- await new Promise((resolve3) => setTimeout(resolve3, delay));
2315
- delay = Math.min(delay * 2, maxDelay);
2316
- continue;
2548
+ } catch (error) {
2549
+ errorCount++;
2550
+ if (errorCount >= MAX_CONSECUTIVE_ERRORS) {
2551
+ throw new ZapierApiError(
2552
+ `Failed to poll after ${errorCount} consecutive errors: ${error instanceof Error ? error.message : String(error)}`,
2553
+ {
2554
+ cause: error
2555
+ }
2556
+ );
2317
2557
  }
2318
2558
  }
2319
2559
  }
2320
- throw new ZapierTimeoutError(
2321
- `Operation timed out after ${maxAttempts} attempts`,
2322
- { attempts: maxAttempts, maxAttempts }
2323
- );
2324
2560
  }
2325
2561
 
2326
2562
  // src/auth.ts
@@ -2375,9 +2611,8 @@ var ZapierApiClient = class {
2375
2611
  searchParams: options.searchParams,
2376
2612
  authRequired: options.authRequired
2377
2613
  }),
2378
- maxAttempts: options.maxAttempts,
2379
2614
  initialDelay: options.initialDelay,
2380
- maxDelay: options.maxDelay,
2615
+ timeoutMs: options.timeoutMs,
2381
2616
  successStatus: options.successStatus,
2382
2617
  pendingStatus: options.pendingStatus,
2383
2618
  resultExtractor: options.resultExtractor
@@ -3085,10 +3320,10 @@ function createSdk(options = {}, initialSdk = {}, initialContext = { meta: {} })
3085
3320
  };
3086
3321
  }
3087
3322
  function createZapierSdkWithoutRegistry(options = {}) {
3088
- 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);
3323
+ 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);
3089
3324
  }
3090
3325
  function createZapierSdk(options = {}) {
3091
3326
  return createZapierSdkWithoutRegistry(options).addPlugin(registryPlugin);
3092
3327
  }
3093
3328
 
3094
- export { ActionKeyPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AuthenticationIdPropertySchema, DebugPropertySchema, InputsPropertySchema, LimitPropertySchema, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, RelayFetchSchema, RelayRequestSchema, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierError, ZapierNotFoundError, ZapierResourceNotFoundError, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, authenticationIdResolver, createFunction, createSdk, createZapierSdk, createZapierSdkWithoutRegistry, fetchPlugin, findFirstAuthenticationPlugin, findUniqueAuthenticationPlugin, formatErrorMessage, getActionPlugin, getAppPlugin, getAuthenticationPlugin, getProfilePlugin, getResolutionOrder, getResolutionOrderForParams, getResolvableParams, getResolver, getResolversForMissingParams, getTokenFromCliLogin, getTokenFromEnv, getTokenFromEnvOrConfig, hasResolver, inputsResolver, isPositional, listActionsPlugin, listAppsPlugin, listAuthenticationsPlugin, listInputFieldsPlugin, loadManifestFromFile, lockVersionPlugin, manifestPlugin, registryPlugin, requestPlugin, resolverRegistry, runActionPlugin };
3329
+ export { ActionKeyPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AuthenticationIdPropertySchema, DEFAULT_CONFIG_PATH, DebugPropertySchema, InputsPropertySchema, LimitPropertySchema, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, RelayFetchSchema, RelayRequestSchema, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierError, ZapierNotFoundError, ZapierResourceNotFoundError, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, authenticationIdResolver, createFunction, createSdk, createZapierSdk, createZapierSdkWithoutRegistry, fetchPlugin, findFirstAuthenticationPlugin, findManifestEntry, findUniqueAuthenticationPlugin, formatErrorMessage, getActionPlugin, getAppPlugin, getAuthenticationPlugin, getPreferredManifestEntryKey, getProfilePlugin, getResolutionOrder, getResolutionOrderForParams, getResolvableParams, getResolver, getResolversForMissingParams, getTokenFromCliLogin, getTokenFromEnv, getTokenFromEnvOrConfig, hasResolver, inputsResolver, isPositional, listActionsPlugin, listAppsPlugin, listAuthenticationsPlugin, listInputFieldsPlugin, manifestPlugin, readManifestFromFile, registryPlugin, requestPlugin, resolverRegistry, runActionPlugin };