zapier-platform-cli 16.3.0 → 16.4.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.
- package/oclif.manifest.json +136 -118
- package/package.json +1 -1
- package/src/generators/index.js +1 -0
- package/src/generators/templates/openai/README.md +3 -0
- package/src/generators/templates/openai/authentication.js +46 -0
- package/src/generators/templates/openai/constants.js +10 -0
- package/src/generators/templates/openai/creates/chat_completion.js +164 -0
- package/src/generators/templates/openai/creates/index.js +7 -0
- package/src/generators/templates/openai/dynamic_dropdowns/index.js +7 -0
- package/src/generators/templates/openai/dynamic_dropdowns/list_models.js +24 -0
- package/src/generators/templates/openai/index.js +33 -0
- package/src/generators/templates/openai/middleware.js +50 -0
- package/src/generators/templates/openai/samples/chat.json +29 -0
- package/src/generators/templates/openai/test/authentication.test.js +66 -0
- package/src/generators/templates/openai/test/chat_completion.test.js +150 -0
- package/src/generators/templates/openai/test/list_models.test.js +51 -0
- package/src/oclif/ZapierBaseCommand.js +1 -1
- package/src/oclif/commands/deprecate.js +42 -8
- package/src/oclif/commands/invoke.js +279 -15
- package/src/utils/api.js +9 -0
- package/src/utils/local.js +266 -2
package/src/utils/local.js
CHANGED
|
@@ -2,8 +2,231 @@ const _ = require('lodash');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
4
|
const { findCorePackageDir } = require('./misc');
|
|
5
|
+
const { BASE_ENDPOINT } = require('../constants');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Wraps Node's http.request() / https.request() so that all requests go via a relay URL.
|
|
9
|
+
* It decides whether to use the http or https module based on the relay URL's protocol.
|
|
10
|
+
*
|
|
11
|
+
* @param {Function} originalHttpRequest - The original http.request function.
|
|
12
|
+
* @param {Function} originalHttpsRequest - The original https.request function.
|
|
13
|
+
* @param {string} relayUrl - The base URL to which we relay. (e.g., 'http://my-relay.test')
|
|
14
|
+
* @param {Object} relayHeaders - Extra headers to add to each request sent to the relay.
|
|
15
|
+
* @returns {Function} A function with the same signature as http(s).request that relays instead.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* const http = require('http');
|
|
19
|
+
* const https = require('https');
|
|
20
|
+
*
|
|
21
|
+
* // Replace https.request with our wrapped version:
|
|
22
|
+
* https.request = wrapHttpRequestFuncWithRelay(
|
|
23
|
+
* http.request,
|
|
24
|
+
* https.request,
|
|
25
|
+
* 'https://my-relay.test',
|
|
26
|
+
* { 'X-Relayed-By': 'MyRelayProxy' }
|
|
27
|
+
* );
|
|
28
|
+
*
|
|
29
|
+
* // Now, calling https.request('https://example.com/hello') will actually
|
|
30
|
+
* // send a request to "https://my-relay.test/example.com/hello"
|
|
31
|
+
* // with X-Relayed-By header attached.
|
|
32
|
+
*/
|
|
33
|
+
function wrapHttpRequestFuncWithRelay(
|
|
34
|
+
originalHttpRequest,
|
|
35
|
+
originalHttpsRequest,
|
|
36
|
+
relayUrl,
|
|
37
|
+
relayHeaders,
|
|
38
|
+
) {
|
|
39
|
+
const parsedRelayUrl = new URL(relayUrl);
|
|
40
|
+
|
|
41
|
+
// Decide if the relay itself is HTTP or HTTPS
|
|
42
|
+
const isRelayHttps = parsedRelayUrl.protocol === 'https:';
|
|
43
|
+
|
|
44
|
+
// Pick which request function to use to talk to the relay
|
|
45
|
+
const relayRequestFunc = isRelayHttps
|
|
46
|
+
? originalHttpsRequest
|
|
47
|
+
: originalHttpRequest;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The actual wrapped request function.
|
|
51
|
+
* Accepts the same arguments as http(s).request:
|
|
52
|
+
* (options[, callback]) or (url[, options][, callback])
|
|
53
|
+
*/
|
|
54
|
+
return function wrappedRequest(originalOptions, originalCallback) {
|
|
55
|
+
let options;
|
|
56
|
+
let callback;
|
|
57
|
+
|
|
58
|
+
// 1. Normalize arguments (string URL vs. options object)
|
|
59
|
+
if (typeof originalOptions === 'string') {
|
|
60
|
+
// Called like request(urlString, [...])
|
|
61
|
+
try {
|
|
62
|
+
const parsedOriginalUrl = new URL(originalOptions);
|
|
63
|
+
|
|
64
|
+
if (typeof originalCallback === 'object') {
|
|
65
|
+
// request(urlString, optionsObject, callback)
|
|
66
|
+
options = { ...originalCallback };
|
|
67
|
+
callback = arguments[2];
|
|
68
|
+
} else {
|
|
69
|
+
// request(urlString, callback) or request(urlString)
|
|
70
|
+
options = {};
|
|
71
|
+
callback = originalCallback;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Merge in the URL parts if not explicitly set in options
|
|
75
|
+
options.protocol = options.protocol || parsedOriginalUrl.protocol;
|
|
76
|
+
options.hostname = options.hostname || parsedOriginalUrl.hostname;
|
|
77
|
+
options.port = options.port || parsedOriginalUrl.port;
|
|
78
|
+
options.path =
|
|
79
|
+
options.path || parsedOriginalUrl.pathname + parsedOriginalUrl.search;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
// If it's not a valid absolute URL, treat it as a path
|
|
82
|
+
// or re-throw if you prefer strictness.
|
|
83
|
+
options = {};
|
|
84
|
+
callback = originalCallback;
|
|
85
|
+
options.path = originalOptions;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
// Called like request(optionsObject, [callback])
|
|
89
|
+
options = { ...originalOptions };
|
|
90
|
+
callback = originalCallback;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 2. Default method and headers
|
|
94
|
+
if (!options.method) {
|
|
95
|
+
options.method = 'GET';
|
|
96
|
+
}
|
|
97
|
+
if (!options.headers) {
|
|
98
|
+
options.headers = {};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 3. Decide whether to relay or not
|
|
102
|
+
// If the request is being sent to the same host:port as our relay,
|
|
103
|
+
// we do NOT want to relay again. We just call the original request.
|
|
104
|
+
const targetHost = (options.hostname || options.host)
|
|
105
|
+
.replaceAll('lcurly-', '{{')
|
|
106
|
+
.replaceAll('-rcurly', '}}');
|
|
107
|
+
const targetPort = options.port ? String(options.port) : '';
|
|
108
|
+
const relayHost = parsedRelayUrl.hostname;
|
|
109
|
+
const relayPort = parsedRelayUrl.port ? String(parsedRelayUrl.port) : '';
|
|
110
|
+
|
|
111
|
+
const isAlreadyRelay =
|
|
112
|
+
targetHost === relayHost &&
|
|
113
|
+
// If no port was specified, assume default port comparison as needed
|
|
114
|
+
(targetPort === relayPort || (!targetPort && !relayPort));
|
|
115
|
+
|
|
116
|
+
if (isAlreadyRelay) {
|
|
117
|
+
// Just call the original function; do *not* re-relay
|
|
118
|
+
const originalFn =
|
|
119
|
+
options.protocol === 'https:'
|
|
120
|
+
? originalHttpsRequest
|
|
121
|
+
: originalHttpRequest;
|
|
122
|
+
return originalFn(options, callback);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 4. Otherwise, build the path we want to relay to
|
|
126
|
+
let finalHost = targetHost;
|
|
127
|
+
if (targetPort && targetPort !== '443') {
|
|
128
|
+
finalHost += `:${targetPort}`;
|
|
129
|
+
}
|
|
130
|
+
const combinedPath = `${parsedRelayUrl.pathname}/${finalHost}${options.path}`;
|
|
131
|
+
|
|
132
|
+
// 5. Build final options for the relay request
|
|
133
|
+
const relayedOptions = {
|
|
134
|
+
protocol: parsedRelayUrl.protocol,
|
|
135
|
+
hostname: relayHost,
|
|
136
|
+
port: relayPort,
|
|
137
|
+
path: combinedPath,
|
|
138
|
+
method: options.method,
|
|
139
|
+
headers: {
|
|
140
|
+
...options.headers,
|
|
141
|
+
...relayHeaders,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// 6. Make the relay request
|
|
146
|
+
const relayReq = relayRequestFunc(relayedOptions, callback);
|
|
147
|
+
return relayReq;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Wraps a fetch function so that all requests get relayed to a specified relay URL.
|
|
153
|
+
* The final relay URL includes: relayUrl + "/" + originalHost + originalPath
|
|
154
|
+
*
|
|
155
|
+
* @param {Function} fetchFunc - The original fetch function (e.g., global.fetch).
|
|
156
|
+
* @param {string} relayUrl - The base URL to which we relay. (e.g. 'https://my-relay.test')
|
|
157
|
+
* @param {Object} relayHeaders - Extra headers to add to each request sent to the relay.
|
|
158
|
+
* @returns {Function} A function with the same signature as `fetch(url, options)`.
|
|
159
|
+
*
|
|
160
|
+
* Usage:
|
|
161
|
+
* const wrappedFetch = wrapFetchWithRelay(
|
|
162
|
+
* fetch,
|
|
163
|
+
* 'https://my-relay.test',
|
|
164
|
+
* { 'X-Relayed-By': 'MyRelayProxy' },
|
|
165
|
+
* );
|
|
166
|
+
*
|
|
167
|
+
* // Now when you do:
|
|
168
|
+
* // wrappedFetch('https://example.com/api/user?id=123', { method: 'POST' });
|
|
169
|
+
* // it actually sends a request to:
|
|
170
|
+
* // https://my-relay.test/example.com/api/user?id=123
|
|
171
|
+
* // with "X-Relayed-By" header included.
|
|
172
|
+
*/
|
|
173
|
+
function wrapFetchWithRelay(fetchFunc, relayUrl, relayHeaders) {
|
|
174
|
+
const parsedRelayUrl = new URL(relayUrl);
|
|
175
|
+
|
|
176
|
+
return async function wrappedFetch(originalUrl, originalOptions = {}) {
|
|
177
|
+
// Attempt to parse the originalUrl as an absolute URL
|
|
178
|
+
const parsedOriginalUrl = new URL(originalUrl);
|
|
179
|
+
|
|
180
|
+
// Build the portion that includes the original host (and port if present)
|
|
181
|
+
let host = parsedOriginalUrl.hostname;
|
|
182
|
+
// If there's a port that isn't 443 (for HTTPS) or 80 (for HTTP), append it
|
|
183
|
+
// (Adjust to your preferences; here we loosely check for 443 only.)
|
|
184
|
+
if (parsedOriginalUrl.port && parsedOriginalUrl.port.toString() !== '443') {
|
|
185
|
+
host += `:${parsedOriginalUrl.port}`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const isAlreadyRelay =
|
|
189
|
+
parsedOriginalUrl.hostname === parsedRelayUrl.hostname &&
|
|
190
|
+
parsedOriginalUrl.port === parsedRelayUrl.port;
|
|
191
|
+
if (isAlreadyRelay) {
|
|
192
|
+
// Just call the original fetch function; do *not* re-relay
|
|
193
|
+
return fetchFunc(originalUrl, originalOptions);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Combine the relay's pathname with the "host + path" from the original
|
|
197
|
+
// For example: relayUrl = http://my-relay.test
|
|
198
|
+
// => parsedRelayUrl.pathname might be '/'
|
|
199
|
+
// => combinedPath = '/example.com:8080/some/path'
|
|
200
|
+
const combinedPath = `${parsedRelayUrl.pathname}/${host}${parsedOriginalUrl.pathname}`;
|
|
201
|
+
|
|
202
|
+
// Merge in the search strings: the relay's own search (if any) plus the original URL's search
|
|
203
|
+
const finalUrl = `${parsedRelayUrl.origin}${combinedPath}${parsedRelayUrl.search}${parsedOriginalUrl.search}`;
|
|
204
|
+
|
|
205
|
+
// Merge the user's headers with the relayHeaders
|
|
206
|
+
const mergedHeaders = {
|
|
207
|
+
...(originalOptions.headers || {}),
|
|
208
|
+
...relayHeaders,
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const finalOptions = {
|
|
212
|
+
...originalOptions,
|
|
213
|
+
headers: mergedHeaders,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Call the real fetch with our new URL and merged options
|
|
217
|
+
return fetchFunc(finalUrl, finalOptions);
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const getLocalAppHandler = ({
|
|
222
|
+
reload = false,
|
|
223
|
+
baseEvent = {},
|
|
224
|
+
appId = null,
|
|
225
|
+
deployKey = null,
|
|
226
|
+
relayAuthenticationId = null,
|
|
227
|
+
beforeRequest = null,
|
|
228
|
+
afterResponse = null,
|
|
229
|
+
} = {}) => {
|
|
7
230
|
const entryPath = `${process.cwd()}/index`;
|
|
8
231
|
const rootPath = path.dirname(require.resolve(entryPath));
|
|
9
232
|
const corePackageDir = findCorePackageDir();
|
|
@@ -24,6 +247,41 @@ const getLocalAppHandler = ({ reload = false, baseEvent = {} } = {}) => {
|
|
|
24
247
|
// maybe we could do require('syntax-error') in the future
|
|
25
248
|
return (event, ctx, callback) => callback(err);
|
|
26
249
|
}
|
|
250
|
+
|
|
251
|
+
if (beforeRequest) {
|
|
252
|
+
appRaw.beforeRequest = [...(appRaw.beforeRequest || []), ...beforeRequest];
|
|
253
|
+
}
|
|
254
|
+
if (afterResponse) {
|
|
255
|
+
appRaw.afterResponse = [...afterResponse, ...(appRaw.afterResponse || [])];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (appId && deployKey && relayAuthenticationId) {
|
|
259
|
+
const relayUrl = `${BASE_ENDPOINT}/api/platform/cli/apps/${appId}/relay`;
|
|
260
|
+
const relayHeaders = {
|
|
261
|
+
'x-relay-authentication-id': relayAuthenticationId,
|
|
262
|
+
'x-deploy-key': deployKey,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const http = require('http');
|
|
266
|
+
const https = require('https');
|
|
267
|
+
const origHttpRequest = http.request;
|
|
268
|
+
const origHttpsRequest = https.request;
|
|
269
|
+
http.request = wrapHttpRequestFuncWithRelay(
|
|
270
|
+
origHttpRequest,
|
|
271
|
+
origHttpsRequest,
|
|
272
|
+
relayUrl,
|
|
273
|
+
relayHeaders,
|
|
274
|
+
);
|
|
275
|
+
https.request = wrapHttpRequestFuncWithRelay(
|
|
276
|
+
origHttpRequest,
|
|
277
|
+
origHttpsRequest,
|
|
278
|
+
relayUrl,
|
|
279
|
+
relayHeaders,
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
global.fetch = wrapFetchWithRelay(global.fetch, relayUrl, relayHeaders);
|
|
283
|
+
}
|
|
284
|
+
|
|
27
285
|
const handler = zapier.createAppHandler(appRaw);
|
|
28
286
|
return (event, ctx, callback) => {
|
|
29
287
|
event = _.merge(
|
|
@@ -40,7 +298,13 @@ const getLocalAppHandler = ({ reload = false, baseEvent = {} } = {}) => {
|
|
|
40
298
|
|
|
41
299
|
// Runs a local app command (./index.js) like {command: 'validate'};
|
|
42
300
|
const localAppCommand = (event) => {
|
|
43
|
-
const handler = getLocalAppHandler(
|
|
301
|
+
const handler = getLocalAppHandler({
|
|
302
|
+
appId: event.appId,
|
|
303
|
+
deployKey: event.deployKey,
|
|
304
|
+
relayAuthenticationId: event.relayAuthenticationId,
|
|
305
|
+
beforeRequest: event.beforeRequest,
|
|
306
|
+
afterResponse: event.afterResponse,
|
|
307
|
+
});
|
|
44
308
|
return new Promise((resolve, reject) => {
|
|
45
309
|
handler(event, {}, (err, resp) => {
|
|
46
310
|
if (err) {
|