@zapier/zapier-sdk-cli 0.30.0 → 0.31.1
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/CHANGELOG.md +21 -0
- package/README.md +34 -13
- package/dist/cli.cjs +473 -17
- package/dist/cli.mjs +476 -20
- package/dist/index.cjs +434 -2
- package/dist/index.mjs +437 -4
- package/dist/package.json +1 -1
- package/dist/src/cli.js +3 -2
- package/dist/src/plugins/cliOverrides/index.d.ts +21 -0
- package/dist/src/plugins/cliOverrides/index.js +19 -0
- package/dist/src/plugins/curl/index.d.ts +17 -0
- package/dist/src/plugins/curl/index.js +234 -0
- package/dist/src/plugins/curl/schemas.d.ts +39 -0
- package/dist/src/plugins/curl/schemas.js +101 -0
- package/dist/src/plugins/curl/utils.d.ts +24 -0
- package/dist/src/plugins/curl/utils.js +141 -0
- package/dist/src/plugins/index.d.ts +2 -0
- package/dist/src/plugins/index.js +2 -0
- package/dist/src/sdk.js +4 -1
- package/dist/src/utils/cli-generator.js +47 -12
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFunction, OutputPropertySchema, DEFAULT_CONFIG_PATH, getOsInfo, getPlatformVersions, getCiPlatform, isCi, createZapierSdkWithoutRegistry, registryPlugin, getReleaseId, getCurrentTimestamp, generateEventId, ZapierValidationError, ZapierUnknownError, batch, toSnakeCase, isCredentialsObject, ZapierError } from '@zapier/zapier-sdk';
|
|
2
2
|
import open from 'open';
|
|
3
|
-
import crypto from 'crypto';
|
|
3
|
+
import crypto, { createHash } from 'crypto';
|
|
4
4
|
import express from 'express';
|
|
5
5
|
import pkceChallenge from 'pkce-challenge';
|
|
6
6
|
import { logout, getConfigPath, getLoggedInUser, getPkceLoginConfig, AUTH_MODE_HEADER, updateLogin } from '@zapier/zapier-sdk-cli-login';
|
|
@@ -10,8 +10,9 @@ import { z } from 'zod';
|
|
|
10
10
|
import { startMcpServer } from '@zapier/zapier-sdk-mcp';
|
|
11
11
|
import { buildSync } from 'esbuild';
|
|
12
12
|
import * as fs from 'fs';
|
|
13
|
+
import { promises, createWriteStream } from 'fs';
|
|
13
14
|
import * as path from 'path';
|
|
14
|
-
import { resolve, join } from 'path';
|
|
15
|
+
import { resolve, join, dirname, basename } from 'path';
|
|
15
16
|
import { mkdir, writeFile, access } from 'fs/promises';
|
|
16
17
|
import * as ts from 'typescript';
|
|
17
18
|
|
|
@@ -271,7 +272,7 @@ var LoginSchema = z.object({
|
|
|
271
272
|
|
|
272
273
|
// package.json
|
|
273
274
|
var package_default = {
|
|
274
|
-
version: "0.
|
|
275
|
+
version: "0.31.1"};
|
|
275
276
|
|
|
276
277
|
// src/telemetry/builders.ts
|
|
277
278
|
function createCliBaseEvent(context = {}) {
|
|
@@ -1607,12 +1608,444 @@ var feedbackPlugin = ({
|
|
|
1607
1608
|
}
|
|
1608
1609
|
};
|
|
1609
1610
|
};
|
|
1611
|
+
var CurlSchema = z.object({
|
|
1612
|
+
url: z.string().describe("Request URL"),
|
|
1613
|
+
request: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]).optional().describe("HTTP method (defaults to GET, or POST if data is provided)"),
|
|
1614
|
+
header: z.array(z.string()).optional().describe("HTTP headers in 'Key: Value' format (repeatable)"),
|
|
1615
|
+
data: z.array(z.string()).optional().describe("HTTP POST data (repeatable, joined with &)"),
|
|
1616
|
+
dataRaw: z.array(z.string()).optional().describe("HTTP POST data without special interpretation (repeatable)"),
|
|
1617
|
+
dataAscii: z.array(z.string()).optional().describe("HTTP POST ASCII data (repeatable)"),
|
|
1618
|
+
dataBinary: z.array(z.string()).optional().describe("HTTP POST binary data (repeatable)"),
|
|
1619
|
+
dataUrlencode: z.array(z.string()).optional().describe("HTTP POST data, URL-encoded (repeatable)"),
|
|
1620
|
+
json: z.string().optional().describe("Send JSON body (sets Content-Type and Accept headers)"),
|
|
1621
|
+
form: z.array(z.string()).optional().describe("Multipart form data as 'name=value' (repeatable)"),
|
|
1622
|
+
formString: z.array(z.string()).optional().describe("Multipart form string field (repeatable)"),
|
|
1623
|
+
get: z.boolean().optional().describe("Force GET method and append data to query string"),
|
|
1624
|
+
head: z.boolean().optional().describe("Fetch headers only (HEAD request)"),
|
|
1625
|
+
location: z.boolean().optional().describe("Follow redirects"),
|
|
1626
|
+
include: z.boolean().optional().describe("Include response headers in output"),
|
|
1627
|
+
output: z.string().optional().describe("Write output to file instead of stdout"),
|
|
1628
|
+
remoteName: z.boolean().optional().describe("Write output to file named like the remote file"),
|
|
1629
|
+
verbose: z.boolean().optional().describe("Verbose output (show request/response headers on stderr)"),
|
|
1630
|
+
silent: z.boolean().optional().describe("Silent mode (suppress errors)"),
|
|
1631
|
+
showError: z.boolean().optional().describe("Show errors even when in silent mode"),
|
|
1632
|
+
fail: z.boolean().optional().describe("Fail silently on HTTP errors (exit code 22)"),
|
|
1633
|
+
failWithBody: z.boolean().optional().describe("Fail on HTTP errors but still output the body"),
|
|
1634
|
+
writeOut: z.string().optional().describe("Output format string after completion (e.g., '%{http_code}')"),
|
|
1635
|
+
maxTime: z.number().optional().describe("Maximum time in seconds for the request"),
|
|
1636
|
+
user: z.string().optional().describe("Basic auth credentials as 'user:password'"),
|
|
1637
|
+
compressed: z.boolean().optional().describe("Request compressed response (sends Accept-Encoding header)"),
|
|
1638
|
+
connectionId: z.union([z.string(), z.number()]).optional().describe("Zapier connection ID for authentication")
|
|
1639
|
+
}).describe("Make HTTP requests through Zapier Relay with curl-like options");
|
|
1640
|
+
var CurlExitError = class extends Error {
|
|
1641
|
+
constructor(message, exitCode) {
|
|
1642
|
+
super(message);
|
|
1643
|
+
this.exitCode = exitCode;
|
|
1644
|
+
this.name = "CurlExitError";
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
function parseHeaderLine(input) {
|
|
1648
|
+
const idx = input.indexOf(":");
|
|
1649
|
+
if (idx === -1) {
|
|
1650
|
+
return null;
|
|
1651
|
+
}
|
|
1652
|
+
const key = input.slice(0, idx).trim();
|
|
1653
|
+
const value = input.slice(idx + 1).trim();
|
|
1654
|
+
if (!key) {
|
|
1655
|
+
return null;
|
|
1656
|
+
}
|
|
1657
|
+
return { key, value };
|
|
1658
|
+
}
|
|
1659
|
+
function basicAuthHeader(userpass) {
|
|
1660
|
+
const idx = userpass.indexOf(":");
|
|
1661
|
+
const user = idx === -1 ? userpass : userpass.slice(0, idx);
|
|
1662
|
+
const pass = idx === -1 ? "" : userpass.slice(idx + 1);
|
|
1663
|
+
const token = Buffer.from(`${user}:${pass}`, "utf8").toString("base64");
|
|
1664
|
+
return `Basic ${token}`;
|
|
1665
|
+
}
|
|
1666
|
+
function deriveRemoteFilename(url) {
|
|
1667
|
+
const path2 = url.pathname;
|
|
1668
|
+
const candidate = path2.endsWith("/") ? "index.html" : basename(path2);
|
|
1669
|
+
return candidate || "index.html";
|
|
1670
|
+
}
|
|
1671
|
+
function decodeWriteOutEscapes(input) {
|
|
1672
|
+
return input.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ");
|
|
1673
|
+
}
|
|
1674
|
+
function formatWriteOut(params) {
|
|
1675
|
+
const { template } = params;
|
|
1676
|
+
const replacements = {
|
|
1677
|
+
"%{http_code}": String(params.httpCode).padStart(3, "0"),
|
|
1678
|
+
"%{time_total}": params.timeTotalSeconds.toFixed(3),
|
|
1679
|
+
"%{size_download}": String(params.sizeDownloadBytes),
|
|
1680
|
+
"%{url_effective}": params.urlEffective,
|
|
1681
|
+
"%{content_type}": params.contentType ?? ""
|
|
1682
|
+
};
|
|
1683
|
+
let out = template;
|
|
1684
|
+
for (const [token, value] of Object.entries(replacements)) {
|
|
1685
|
+
out = out.split(token).join(value);
|
|
1686
|
+
}
|
|
1687
|
+
return decodeWriteOutEscapes(out);
|
|
1688
|
+
}
|
|
1689
|
+
function appendQueryParams(url, dataParts) {
|
|
1690
|
+
const out = new URL(url.toString());
|
|
1691
|
+
for (const part of dataParts) {
|
|
1692
|
+
const segments = part.split("&");
|
|
1693
|
+
for (const seg of segments) {
|
|
1694
|
+
if (!seg) continue;
|
|
1695
|
+
const idx = seg.indexOf("=");
|
|
1696
|
+
if (idx === -1) {
|
|
1697
|
+
out.searchParams.append(seg, "");
|
|
1698
|
+
} else {
|
|
1699
|
+
out.searchParams.append(seg.slice(0, idx), seg.slice(idx + 1));
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
return out;
|
|
1704
|
+
}
|
|
1705
|
+
async function readAllStdin() {
|
|
1706
|
+
const chunks = [];
|
|
1707
|
+
for await (const chunk of process.stdin) {
|
|
1708
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1709
|
+
}
|
|
1710
|
+
return Buffer.concat(chunks);
|
|
1711
|
+
}
|
|
1712
|
+
async function resolveDataArgText(raw) {
|
|
1713
|
+
if (!raw.startsWith("@")) {
|
|
1714
|
+
return raw;
|
|
1715
|
+
}
|
|
1716
|
+
const source = raw.slice(1);
|
|
1717
|
+
if (source === "-") {
|
|
1718
|
+
const buf2 = await readAllStdin();
|
|
1719
|
+
return buf2.toString("utf8");
|
|
1720
|
+
}
|
|
1721
|
+
const buf = await promises.readFile(source);
|
|
1722
|
+
return buf.toString("utf8");
|
|
1723
|
+
}
|
|
1724
|
+
async function resolveDataArgBinary(raw) {
|
|
1725
|
+
if (!raw.startsWith("@")) {
|
|
1726
|
+
return Buffer.from(raw, "utf8");
|
|
1727
|
+
}
|
|
1728
|
+
const source = raw.slice(1);
|
|
1729
|
+
if (source === "-") {
|
|
1730
|
+
return await readAllStdin();
|
|
1731
|
+
}
|
|
1732
|
+
return await promises.readFile(source);
|
|
1733
|
+
}
|
|
1734
|
+
async function buildFormData(formArgs, formStringArgs) {
|
|
1735
|
+
if (typeof FormData === "undefined") {
|
|
1736
|
+
throw new CurlExitError(
|
|
1737
|
+
"FormData is not available in this runtime; cannot use --form.",
|
|
1738
|
+
2
|
|
1739
|
+
);
|
|
1740
|
+
}
|
|
1741
|
+
const fd = new FormData();
|
|
1742
|
+
const addField = async (item, forceString) => {
|
|
1743
|
+
const idx = item.indexOf("=");
|
|
1744
|
+
if (idx === -1) {
|
|
1745
|
+
throw new CurlExitError(
|
|
1746
|
+
`Invalid form field: '${item}'. Expected 'name=value' or 'name=@file'.`,
|
|
1747
|
+
2
|
|
1748
|
+
);
|
|
1749
|
+
}
|
|
1750
|
+
const name = item.slice(0, idx);
|
|
1751
|
+
const value = item.slice(idx + 1);
|
|
1752
|
+
if (!name) {
|
|
1753
|
+
throw new CurlExitError(
|
|
1754
|
+
`Invalid form field: '${item}'. Field name cannot be empty.`,
|
|
1755
|
+
2
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1758
|
+
if (!forceString && value.startsWith("@")) {
|
|
1759
|
+
const filePath = value.slice(1);
|
|
1760
|
+
const buf = filePath === "-" ? await readAllStdin() : await promises.readFile(filePath);
|
|
1761
|
+
if (typeof Blob === "undefined") {
|
|
1762
|
+
fd.append(name, buf.toString("utf8"));
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
const blob = new Blob([buf]);
|
|
1766
|
+
const filename = filePath === "-" ? `stdin-${createHash("sha1").update(buf).digest("hex").slice(0, 8)}` : basename(filePath);
|
|
1767
|
+
fd.append(name, blob, filename);
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
fd.append(name, value);
|
|
1771
|
+
};
|
|
1772
|
+
for (const item of formArgs) {
|
|
1773
|
+
await addField(item, false);
|
|
1774
|
+
}
|
|
1775
|
+
for (const item of formStringArgs) {
|
|
1776
|
+
await addField(item, true);
|
|
1777
|
+
}
|
|
1778
|
+
return fd;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
// src/plugins/curl/index.ts
|
|
1782
|
+
var curlPlugin = ({
|
|
1783
|
+
sdk
|
|
1784
|
+
}) => {
|
|
1785
|
+
async function curl(options) {
|
|
1786
|
+
const {
|
|
1787
|
+
url: rawUrl,
|
|
1788
|
+
request,
|
|
1789
|
+
header = [],
|
|
1790
|
+
data = [],
|
|
1791
|
+
dataRaw = [],
|
|
1792
|
+
dataAscii = [],
|
|
1793
|
+
dataBinary = [],
|
|
1794
|
+
dataUrlencode = [],
|
|
1795
|
+
json,
|
|
1796
|
+
form = [],
|
|
1797
|
+
formString = [],
|
|
1798
|
+
get: forceGet,
|
|
1799
|
+
head: forceHead,
|
|
1800
|
+
location,
|
|
1801
|
+
include,
|
|
1802
|
+
output,
|
|
1803
|
+
remoteName,
|
|
1804
|
+
verbose,
|
|
1805
|
+
silent,
|
|
1806
|
+
showError,
|
|
1807
|
+
fail,
|
|
1808
|
+
failWithBody,
|
|
1809
|
+
writeOut,
|
|
1810
|
+
maxTime,
|
|
1811
|
+
user,
|
|
1812
|
+
compressed,
|
|
1813
|
+
connectionId
|
|
1814
|
+
} = options;
|
|
1815
|
+
const parsedUrl = new URL(rawUrl);
|
|
1816
|
+
const headers = {};
|
|
1817
|
+
for (const h of header) {
|
|
1818
|
+
const parsed = parseHeaderLine(h);
|
|
1819
|
+
if (parsed) {
|
|
1820
|
+
headers[parsed.key] = parsed.value;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
if (user) {
|
|
1824
|
+
headers["Authorization"] = basicAuthHeader(user);
|
|
1825
|
+
}
|
|
1826
|
+
if (compressed) {
|
|
1827
|
+
headers["Accept-Encoding"] = "gzip, deflate, br";
|
|
1828
|
+
}
|
|
1829
|
+
const rawTextDataArgs = [...data, ...dataRaw, ...dataAscii];
|
|
1830
|
+
const rawBinaryDataArgs = [...dataBinary];
|
|
1831
|
+
const rawUrlencodeArgs = [...dataUrlencode];
|
|
1832
|
+
const hasForm = form.length > 0 || formString.length > 0;
|
|
1833
|
+
const hasJson = json !== void 0;
|
|
1834
|
+
const hasAnyData = hasJson || hasForm || rawTextDataArgs.length > 0 || rawBinaryDataArgs.length > 0 || rawUrlencodeArgs.length > 0;
|
|
1835
|
+
let method = "GET";
|
|
1836
|
+
if (forceHead) {
|
|
1837
|
+
method = "HEAD";
|
|
1838
|
+
} else if (request) {
|
|
1839
|
+
method = request;
|
|
1840
|
+
} else if (forceGet) {
|
|
1841
|
+
method = "GET";
|
|
1842
|
+
} else if (hasAnyData) {
|
|
1843
|
+
method = "POST";
|
|
1844
|
+
}
|
|
1845
|
+
let body;
|
|
1846
|
+
let effectiveUrl = parsedUrl;
|
|
1847
|
+
if (hasJson) {
|
|
1848
|
+
if (!headers["Content-Type"]) {
|
|
1849
|
+
headers["Content-Type"] = "application/json";
|
|
1850
|
+
}
|
|
1851
|
+
if (!headers["Accept"]) {
|
|
1852
|
+
headers["Accept"] = "application/json";
|
|
1853
|
+
}
|
|
1854
|
+
body = json;
|
|
1855
|
+
} else if (hasForm) {
|
|
1856
|
+
body = await buildFormData(form, formString);
|
|
1857
|
+
} else {
|
|
1858
|
+
const resolvedTextParts = [];
|
|
1859
|
+
for (const raw of rawTextDataArgs) {
|
|
1860
|
+
resolvedTextParts.push(await resolveDataArgText(raw));
|
|
1861
|
+
}
|
|
1862
|
+
const resolvedUrlEncodeParts = [];
|
|
1863
|
+
for (const raw of rawUrlencodeArgs) {
|
|
1864
|
+
if (raw.startsWith("@")) {
|
|
1865
|
+
const content = await resolveDataArgText(raw);
|
|
1866
|
+
resolvedUrlEncodeParts.push(encodeURIComponent(content));
|
|
1867
|
+
continue;
|
|
1868
|
+
}
|
|
1869
|
+
const atIdx = raw.indexOf("@");
|
|
1870
|
+
const eqIdx = raw.indexOf("=");
|
|
1871
|
+
if (eqIdx !== -1) {
|
|
1872
|
+
const key = raw.slice(0, eqIdx);
|
|
1873
|
+
const value = raw.slice(eqIdx + 1);
|
|
1874
|
+
resolvedUrlEncodeParts.push(
|
|
1875
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
|
1876
|
+
);
|
|
1877
|
+
} else if (atIdx !== -1) {
|
|
1878
|
+
const key = raw.slice(0, atIdx);
|
|
1879
|
+
const filePath = raw.slice(atIdx + 1);
|
|
1880
|
+
const buf2 = filePath === "-" ? await readAllStdin() : await promises.readFile(filePath);
|
|
1881
|
+
resolvedUrlEncodeParts.push(
|
|
1882
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(buf2.toString("utf8"))}`
|
|
1883
|
+
);
|
|
1884
|
+
} else {
|
|
1885
|
+
resolvedUrlEncodeParts.push(encodeURIComponent(raw));
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
const resolvedBinaryParts = [];
|
|
1889
|
+
for (const raw of rawBinaryDataArgs) {
|
|
1890
|
+
resolvedBinaryParts.push(await resolveDataArgBinary(raw));
|
|
1891
|
+
}
|
|
1892
|
+
const allTextParts = [...resolvedTextParts, ...resolvedUrlEncodeParts];
|
|
1893
|
+
if (forceGet && allTextParts.length > 0) {
|
|
1894
|
+
effectiveUrl = appendQueryParams(parsedUrl, allTextParts);
|
|
1895
|
+
} else if (resolvedBinaryParts.length > 0) {
|
|
1896
|
+
body = Buffer.concat(resolvedBinaryParts);
|
|
1897
|
+
} else if (allTextParts.length > 0) {
|
|
1898
|
+
body = allTextParts.join("&");
|
|
1899
|
+
if (!headers["Content-Type"]) {
|
|
1900
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
const redirect = location ? "follow" : "manual";
|
|
1905
|
+
if (verbose && !silent) {
|
|
1906
|
+
process.stderr.write(`> ${method} ${effectiveUrl.toString()}
|
|
1907
|
+
`);
|
|
1908
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
1909
|
+
process.stderr.write(`> ${k}: ${v}
|
|
1910
|
+
`);
|
|
1911
|
+
}
|
|
1912
|
+
process.stderr.write(">\n");
|
|
1913
|
+
}
|
|
1914
|
+
const signal = maxTime ? AbortSignal.timeout(maxTime * 1e3) : void 0;
|
|
1915
|
+
const start = performance.now();
|
|
1916
|
+
const response = await sdk.fetch(effectiveUrl.toString(), {
|
|
1917
|
+
method,
|
|
1918
|
+
headers,
|
|
1919
|
+
body,
|
|
1920
|
+
redirect,
|
|
1921
|
+
signal,
|
|
1922
|
+
connectionId
|
|
1923
|
+
});
|
|
1924
|
+
const timeTotalSeconds = (performance.now() - start) / 1e3;
|
|
1925
|
+
if (verbose && !silent) {
|
|
1926
|
+
process.stderr.write(
|
|
1927
|
+
`< HTTP ${response.status} ${response.statusText}
|
|
1928
|
+
`
|
|
1929
|
+
);
|
|
1930
|
+
response.headers.forEach((value, key) => {
|
|
1931
|
+
process.stderr.write(`< ${key}: ${value}
|
|
1932
|
+
`);
|
|
1933
|
+
});
|
|
1934
|
+
process.stderr.write("<\n");
|
|
1935
|
+
}
|
|
1936
|
+
const isHttpError = response.status >= 400;
|
|
1937
|
+
const shouldFail = (fail || failWithBody) && isHttpError;
|
|
1938
|
+
const shouldOutputBody = !shouldFail || !!failWithBody;
|
|
1939
|
+
const headerText = include ? `HTTP ${response.status} ${response.statusText}
|
|
1940
|
+
${Array.from(
|
|
1941
|
+
response.headers.entries()
|
|
1942
|
+
).map(([k, v]) => `${k}: ${v}`).join("\n")}
|
|
1943
|
+
|
|
1944
|
+
` : "";
|
|
1945
|
+
let bodyBytes = 0;
|
|
1946
|
+
const buf = shouldOutputBody ? Buffer.from(await response.arrayBuffer()) : Buffer.alloc(0);
|
|
1947
|
+
bodyBytes = buf.length;
|
|
1948
|
+
const outputFile = output && output !== "-" ? output : remoteName ? deriveRemoteFilename(parsedUrl) : void 0;
|
|
1949
|
+
if (outputFile) {
|
|
1950
|
+
const dir = dirname(outputFile);
|
|
1951
|
+
if (dir !== ".") {
|
|
1952
|
+
await promises.mkdir(dir, { recursive: true });
|
|
1953
|
+
}
|
|
1954
|
+
const ws = createWriteStream(outputFile);
|
|
1955
|
+
if (headerText) {
|
|
1956
|
+
ws.write(headerText);
|
|
1957
|
+
}
|
|
1958
|
+
if (buf.length) {
|
|
1959
|
+
ws.write(buf);
|
|
1960
|
+
}
|
|
1961
|
+
await new Promise((resolve4, reject) => {
|
|
1962
|
+
ws.end(() => resolve4());
|
|
1963
|
+
ws.on("error", reject);
|
|
1964
|
+
});
|
|
1965
|
+
} else {
|
|
1966
|
+
if (headerText) {
|
|
1967
|
+
process.stdout.write(headerText);
|
|
1968
|
+
}
|
|
1969
|
+
if (buf.length) {
|
|
1970
|
+
process.stdout.write(buf);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
if (writeOut) {
|
|
1974
|
+
const formatted = formatWriteOut({
|
|
1975
|
+
template: writeOut,
|
|
1976
|
+
urlEffective: response.url || effectiveUrl.toString(),
|
|
1977
|
+
httpCode: response.status,
|
|
1978
|
+
timeTotalSeconds,
|
|
1979
|
+
sizeDownloadBytes: bodyBytes,
|
|
1980
|
+
contentType: response.headers.get("content-type")
|
|
1981
|
+
});
|
|
1982
|
+
process.stdout.write(formatted);
|
|
1983
|
+
}
|
|
1984
|
+
if (shouldFail) {
|
|
1985
|
+
if (!silent || showError) {
|
|
1986
|
+
process.stderr.write(
|
|
1987
|
+
`curl: (22) The requested URL returned error: ${response.status}
|
|
1988
|
+
`
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1991
|
+
throw new CurlExitError("HTTP request failed", 22);
|
|
1992
|
+
}
|
|
1993
|
+
return void 0;
|
|
1994
|
+
}
|
|
1995
|
+
return {
|
|
1996
|
+
curl,
|
|
1997
|
+
context: {
|
|
1998
|
+
meta: {
|
|
1999
|
+
curl: {
|
|
2000
|
+
description: "Make authenticated HTTP requests to any API through Zapier. Pass a connection ID to automatically inject the user's stored credentials (OAuth tokens, API keys, etc.) into the outgoing request. Use it in place of the native curl command with additional Zapier-specific options.",
|
|
2001
|
+
categories: ["http"],
|
|
2002
|
+
inputSchema: CurlSchema,
|
|
2003
|
+
aliases: {
|
|
2004
|
+
request: "X",
|
|
2005
|
+
header: "H",
|
|
2006
|
+
data: "d",
|
|
2007
|
+
form: "F",
|
|
2008
|
+
get: "G",
|
|
2009
|
+
head: "I",
|
|
2010
|
+
location: "L",
|
|
2011
|
+
include: "i",
|
|
2012
|
+
output: "o",
|
|
2013
|
+
remoteName: "O",
|
|
2014
|
+
verbose: "v",
|
|
2015
|
+
silent: "s",
|
|
2016
|
+
showError: "S",
|
|
2017
|
+
writeOut: "w",
|
|
2018
|
+
maxTime: "m",
|
|
2019
|
+
user: "u"
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
};
|
|
2026
|
+
|
|
2027
|
+
// src/plugins/cliOverrides/index.ts
|
|
2028
|
+
var cliOverridesPlugin = ({ context }) => {
|
|
2029
|
+
if (!context.meta.fetch) {
|
|
2030
|
+
return { context: { meta: {} } };
|
|
2031
|
+
}
|
|
2032
|
+
return {
|
|
2033
|
+
context: {
|
|
2034
|
+
meta: {
|
|
2035
|
+
fetch: {
|
|
2036
|
+
...context.meta.fetch,
|
|
2037
|
+
categories: [...context.meta.fetch.categories || [], "deprecated"]
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
};
|
|
2042
|
+
};
|
|
1610
2043
|
|
|
1611
2044
|
// src/sdk.ts
|
|
1612
2045
|
function createZapierCliSdk(options = {}) {
|
|
1613
2046
|
return createZapierSdkWithoutRegistry({
|
|
1614
2047
|
...options
|
|
1615
|
-
}).addPlugin(generateAppTypesPlugin).addPlugin(buildManifestPlugin).addPlugin(bundleCodePlugin).addPlugin(getLoginConfigPathPlugin).addPlugin(addPlugin).addPlugin(feedbackPlugin).addPlugin(mcpPlugin).addPlugin(loginPlugin).addPlugin(logoutPlugin).addPlugin(registryPlugin);
|
|
2048
|
+
}).addPlugin(generateAppTypesPlugin).addPlugin(buildManifestPlugin).addPlugin(bundleCodePlugin).addPlugin(getLoginConfigPathPlugin).addPlugin(addPlugin).addPlugin(feedbackPlugin).addPlugin(curlPlugin).addPlugin(mcpPlugin).addPlugin(loginPlugin).addPlugin(logoutPlugin).addPlugin(cliOverridesPlugin).addPlugin(registryPlugin);
|
|
1616
2049
|
}
|
|
1617
2050
|
|
|
1618
2051
|
export { buildCliCommandExecutedEvent, createZapierCliSdk };
|
package/dist/package.json
CHANGED
package/dist/src/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ const program = new Command();
|
|
|
9
9
|
program
|
|
10
10
|
.name("zapier-sdk")
|
|
11
11
|
.description("CLI for Zapier SDK")
|
|
12
|
-
.version(packageJson.version,
|
|
12
|
+
.version(packageJson.version, undefined, "Display version number")
|
|
13
13
|
.option("--debug", "Enable debug logging")
|
|
14
14
|
.option("--base-url <url>", "Base URL for Zapier API endpoints")
|
|
15
15
|
.option("--credentials <token>", "Authentication token")
|
|
@@ -18,7 +18,8 @@ program
|
|
|
18
18
|
.option("--credentials-base-url <url>", "Base URL for authentication endpoints")
|
|
19
19
|
.option("--tracking-base-url <url>", "Base URL for Zapier tracking endpoints")
|
|
20
20
|
.option("--max-network-retries <count>", "Max retries for rate-limited requests (default: 3)")
|
|
21
|
-
.option("--max-network-retry-delay-ms <ms>", "Max delay in ms to wait for rate limit retry (default: 60000)")
|
|
21
|
+
.option("--max-network-retry-delay-ms <ms>", "Max delay in ms to wait for rate limit retry (default: 60000)")
|
|
22
|
+
.helpOption("-h, --help", "Display help for command");
|
|
22
23
|
// Check for debug flag early (support both flag and env var)
|
|
23
24
|
const isDebugMode = process.env.DEBUG === "true" || process.argv.includes("--debug");
|
|
24
25
|
// Helper to get flag value from argv
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Plugin } from "@zapier/zapier-sdk";
|
|
2
|
+
interface FetchMeta {
|
|
3
|
+
categories?: string[];
|
|
4
|
+
}
|
|
5
|
+
interface CliOverridesProvides {
|
|
6
|
+
context: {
|
|
7
|
+
meta: {
|
|
8
|
+
fetch?: FetchMeta;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* CLI-specific metadata overrides.
|
|
14
|
+
* Adds "deprecated" category to fetch so it's hidden from CLI help.
|
|
15
|
+
*/
|
|
16
|
+
export declare const cliOverridesPlugin: Plugin<{}, {
|
|
17
|
+
meta: {
|
|
18
|
+
fetch?: FetchMeta;
|
|
19
|
+
};
|
|
20
|
+
}, CliOverridesProvides>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-specific metadata overrides.
|
|
3
|
+
* Adds "deprecated" category to fetch so it's hidden from CLI help.
|
|
4
|
+
*/
|
|
5
|
+
export const cliOverridesPlugin = ({ context }) => {
|
|
6
|
+
if (!context.meta.fetch) {
|
|
7
|
+
return { context: { meta: {} } };
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
context: {
|
|
11
|
+
meta: {
|
|
12
|
+
fetch: {
|
|
13
|
+
...context.meta.fetch,
|
|
14
|
+
categories: [...(context.meta.fetch.categories || []), "deprecated"],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Plugin, FetchPluginProvides } from "@zapier/zapier-sdk";
|
|
2
|
+
import { CurlSchema, type CurlOptions } from "./schemas";
|
|
3
|
+
export interface CurlPluginProvides {
|
|
4
|
+
curl: (options: CurlOptions) => Promise<undefined>;
|
|
5
|
+
context: {
|
|
6
|
+
meta: {
|
|
7
|
+
curl: {
|
|
8
|
+
inputSchema: typeof CurlSchema;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
type SdkWithFetch = FetchPluginProvides["fetch"] extends infer F ? {
|
|
14
|
+
fetch: F;
|
|
15
|
+
} : never;
|
|
16
|
+
export declare const curlPlugin: Plugin<SdkWithFetch, {}, CurlPluginProvides>;
|
|
17
|
+
export {};
|