zapier-platform-cli 16.3.1 → 16.5.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 +203 -134
- package/package.json +1 -1
- package/src/oclif/ZapierBaseCommand.js +1 -1
- package/src/oclif/commands/deprecate.js +42 -8
- package/src/oclif/commands/invoke.js +278 -14
- package/src/oclif/commands/legacy.js +61 -0
- package/src/oclif/commands/promote.js +0 -5
- package/src/oclif/commands/versions.js +28 -4
- package/src/oclif/oCommands.js +1 -0
- package/src/utils/api.js +9 -0
- package/src/utils/local.js +266 -2
|
@@ -15,6 +15,12 @@ const BaseCommand = require('../ZapierBaseCommand');
|
|
|
15
15
|
const { buildFlags } = require('../buildFlags');
|
|
16
16
|
const { localAppCommand, getLocalAppHandler } = require('../../utils/local');
|
|
17
17
|
const { startSpinner, endSpinner } = require('../../utils/display');
|
|
18
|
+
const {
|
|
19
|
+
getLinkedAppConfig,
|
|
20
|
+
listAuthentications,
|
|
21
|
+
readCredentials,
|
|
22
|
+
} = require('../../utils/api');
|
|
23
|
+
const { AUTH_KEY } = require('../../constants');
|
|
18
24
|
|
|
19
25
|
const ACTION_TYPE_PLURALS = {
|
|
20
26
|
trigger: 'triggers',
|
|
@@ -235,9 +241,88 @@ const appendEnv = async (vars, prefix = '') => {
|
|
|
235
241
|
);
|
|
236
242
|
};
|
|
237
243
|
|
|
238
|
-
const
|
|
244
|
+
const replaceDoubleCurlies = async (request) => {
|
|
245
|
+
// Use lcurly-fieldName-rcurly instead of {{fieldName}} to bypass node-fetch's
|
|
246
|
+
// URL validation in case the variable is used in a URL.
|
|
247
|
+
if (request.url) {
|
|
248
|
+
request.url = request.url
|
|
249
|
+
.replaceAll('{{', 'lcurly-')
|
|
250
|
+
.replaceAll('}}', '-rcurly');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// The authorization header may confuse zapier.com and it's relay's job to add
|
|
254
|
+
// it, so we delete it here.
|
|
255
|
+
delete request.headers.authorization;
|
|
256
|
+
delete request.headers.Authorization;
|
|
257
|
+
|
|
258
|
+
return request;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const restoreDoubleCurlies = async (response) => {
|
|
262
|
+
if (response.url) {
|
|
263
|
+
response.url = response.url
|
|
264
|
+
.replaceAll('lcurly-', '{{')
|
|
265
|
+
.replaceAll('-rcurly', '}}');
|
|
266
|
+
}
|
|
267
|
+
if (response.request?.url) {
|
|
268
|
+
response.request.url = response.request.url
|
|
269
|
+
.replaceAll('lcurly-', '{{')
|
|
270
|
+
.replaceAll('-rcurly', '}}');
|
|
271
|
+
}
|
|
272
|
+
return response;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const localAppCommandWithRelayErrorHandler = async (args) => {
|
|
276
|
+
if (args.relayAuthenticationId) {
|
|
277
|
+
args = {
|
|
278
|
+
...args,
|
|
279
|
+
beforeRequest: [replaceDoubleCurlies],
|
|
280
|
+
afterResponse: [restoreDoubleCurlies],
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let output;
|
|
285
|
+
try {
|
|
286
|
+
output = await localAppCommand(args);
|
|
287
|
+
} catch (outerError) {
|
|
288
|
+
if (outerError.name === 'ResponseError') {
|
|
289
|
+
let response;
|
|
290
|
+
try {
|
|
291
|
+
response = JSON.parse(outerError.message);
|
|
292
|
+
} catch (innerError) {
|
|
293
|
+
throw outerError;
|
|
294
|
+
}
|
|
295
|
+
if (typeof response.content === 'string') {
|
|
296
|
+
const match = response.content.match(/domain filter `([^`]+)`/);
|
|
297
|
+
if (!match) {
|
|
298
|
+
throw outerError;
|
|
299
|
+
}
|
|
300
|
+
const domainFilter = match[1];
|
|
301
|
+
const requestUrl = response.request.url
|
|
302
|
+
.replaceAll('lcurly-', '{{')
|
|
303
|
+
.replaceAll('-rcurly', '}}');
|
|
304
|
+
throw new Error(
|
|
305
|
+
`Request to ${requestUrl} was blocked. ` +
|
|
306
|
+
`Only these domain names are allowed: ${domainFilter}. ` +
|
|
307
|
+
'Contact Zapier team to verify your domain filter setting.',
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
throw outerError;
|
|
312
|
+
}
|
|
313
|
+
return output;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const testAuth = async (
|
|
317
|
+
authId,
|
|
318
|
+
authData,
|
|
319
|
+
meta,
|
|
320
|
+
zcacheTestObj,
|
|
321
|
+
appId,
|
|
322
|
+
deployKey,
|
|
323
|
+
) => {
|
|
239
324
|
startSpinner('Invoking authentication.test');
|
|
240
|
-
const result = await
|
|
325
|
+
const result = await localAppCommandWithRelayErrorHandler({
|
|
241
326
|
command: 'execute',
|
|
242
327
|
method: 'authentication.test',
|
|
243
328
|
bundle: {
|
|
@@ -250,13 +335,31 @@ const testAuth = async (authData, meta, zcacheTestObj) => {
|
|
|
250
335
|
zcacheTestObj,
|
|
251
336
|
customLogger,
|
|
252
337
|
calledFromCliInvoke: true,
|
|
338
|
+
appId,
|
|
339
|
+
deployKey,
|
|
340
|
+
relayAuthenticationId: authId,
|
|
253
341
|
});
|
|
254
342
|
endSpinner();
|
|
255
343
|
return result;
|
|
256
344
|
};
|
|
257
345
|
|
|
258
|
-
const getAuthLabel = async (
|
|
259
|
-
|
|
346
|
+
const getAuthLabel = async (
|
|
347
|
+
labelTemplate,
|
|
348
|
+
authId,
|
|
349
|
+
authData,
|
|
350
|
+
meta,
|
|
351
|
+
zcacheTestObj,
|
|
352
|
+
appId,
|
|
353
|
+
deployKey,
|
|
354
|
+
) => {
|
|
355
|
+
const testResult = await testAuth(
|
|
356
|
+
authId,
|
|
357
|
+
authData,
|
|
358
|
+
meta,
|
|
359
|
+
zcacheTestObj,
|
|
360
|
+
appId,
|
|
361
|
+
deployKey,
|
|
362
|
+
);
|
|
260
363
|
labelTemplate = labelTemplate.replace('__', '.');
|
|
261
364
|
const tpl = _.template(labelTemplate, { interpolate: /{{([\s\S]+?)}}/g });
|
|
262
365
|
return tpl({ ...testResult, bundle: { authData, inputData: testResult } });
|
|
@@ -632,10 +735,13 @@ class InvokeCommand extends BaseCommand {
|
|
|
632
735
|
field,
|
|
633
736
|
appDefinition,
|
|
634
737
|
inputData,
|
|
738
|
+
authId,
|
|
635
739
|
authData,
|
|
636
740
|
timezone,
|
|
637
741
|
zcacheTestObj,
|
|
638
742
|
cursorTestObj,
|
|
743
|
+
appId,
|
|
744
|
+
deployKey,
|
|
639
745
|
) {
|
|
640
746
|
const message = formatFieldDisplay(field) + ':';
|
|
641
747
|
if (field.dynamic) {
|
|
@@ -655,16 +761,19 @@ class InvokeCommand extends BaseCommand {
|
|
|
655
761
|
'triggers',
|
|
656
762
|
trigger,
|
|
657
763
|
inputData,
|
|
764
|
+
authId,
|
|
658
765
|
authData,
|
|
659
766
|
meta,
|
|
660
767
|
timezone,
|
|
661
768
|
zcacheTestObj,
|
|
662
769
|
cursorTestObj,
|
|
770
|
+
appId,
|
|
771
|
+
deployKey,
|
|
663
772
|
);
|
|
664
773
|
return this.promptWithList(
|
|
665
774
|
message,
|
|
666
775
|
choices.map((c) => {
|
|
667
|
-
const id = c[idField]
|
|
776
|
+
const id = c[idField] ?? 'null';
|
|
668
777
|
const label = getLabelForDynamicDropdown(c, labelField, idField);
|
|
669
778
|
return {
|
|
670
779
|
name: `${label} (${id})`,
|
|
@@ -685,11 +794,14 @@ class InvokeCommand extends BaseCommand {
|
|
|
685
794
|
inputData,
|
|
686
795
|
inputFields,
|
|
687
796
|
appDefinition,
|
|
797
|
+
authId,
|
|
688
798
|
authData,
|
|
689
799
|
meta,
|
|
690
800
|
timezone,
|
|
691
801
|
zcacheTestObj,
|
|
692
802
|
cursorTestObj,
|
|
803
|
+
appId,
|
|
804
|
+
deployKey,
|
|
693
805
|
) {
|
|
694
806
|
const missingFields = getMissingRequiredInputFields(inputData, inputFields);
|
|
695
807
|
if (missingFields.length) {
|
|
@@ -704,10 +816,13 @@ class InvokeCommand extends BaseCommand {
|
|
|
704
816
|
f,
|
|
705
817
|
appDefinition,
|
|
706
818
|
inputData,
|
|
819
|
+
authId,
|
|
707
820
|
authData,
|
|
708
821
|
timezone,
|
|
709
822
|
zcacheTestObj,
|
|
710
823
|
cursorTestObj,
|
|
824
|
+
appId,
|
|
825
|
+
deployKey,
|
|
711
826
|
);
|
|
712
827
|
}
|
|
713
828
|
}
|
|
@@ -717,10 +832,13 @@ class InvokeCommand extends BaseCommand {
|
|
|
717
832
|
inputData,
|
|
718
833
|
inputFields,
|
|
719
834
|
appDefinition,
|
|
835
|
+
authId,
|
|
720
836
|
authData,
|
|
721
837
|
timezone,
|
|
722
838
|
zcacheTestObj,
|
|
723
839
|
cursorTestObj,
|
|
840
|
+
appId,
|
|
841
|
+
deployKey,
|
|
724
842
|
) {
|
|
725
843
|
inputFields = inputFields.filter((f) => f.key);
|
|
726
844
|
if (!inputFields.length) {
|
|
@@ -768,10 +886,13 @@ class InvokeCommand extends BaseCommand {
|
|
|
768
886
|
field,
|
|
769
887
|
appDefinition,
|
|
770
888
|
inputData,
|
|
889
|
+
authId,
|
|
771
890
|
authData,
|
|
772
891
|
timezone,
|
|
773
892
|
zcacheTestObj,
|
|
774
893
|
cursorTestObj,
|
|
894
|
+
appId,
|
|
895
|
+
deployKey,
|
|
775
896
|
);
|
|
776
897
|
}
|
|
777
898
|
}
|
|
@@ -780,31 +901,40 @@ class InvokeCommand extends BaseCommand {
|
|
|
780
901
|
inputData,
|
|
781
902
|
inputFields,
|
|
782
903
|
appDefinition,
|
|
904
|
+
authId,
|
|
783
905
|
authData,
|
|
784
906
|
meta,
|
|
785
907
|
timezone,
|
|
786
908
|
zcacheTestObj,
|
|
787
909
|
cursorTestObj,
|
|
910
|
+
appId,
|
|
911
|
+
deployKey,
|
|
788
912
|
) {
|
|
789
913
|
await this.promptOrErrorForRequiredInputFields(
|
|
790
914
|
inputData,
|
|
791
915
|
inputFields,
|
|
792
916
|
appDefinition,
|
|
917
|
+
authId,
|
|
793
918
|
authData,
|
|
794
919
|
meta,
|
|
795
920
|
timezone,
|
|
796
921
|
zcacheTestObj,
|
|
797
922
|
cursorTestObj,
|
|
923
|
+
appId,
|
|
924
|
+
deployKey,
|
|
798
925
|
);
|
|
799
926
|
if (!this.nonInteractive && !meta.isFillingDynamicDropdown) {
|
|
800
927
|
await this.promptForInputFieldEdit(
|
|
801
928
|
inputData,
|
|
802
929
|
inputFields,
|
|
803
930
|
appDefinition,
|
|
931
|
+
authId,
|
|
804
932
|
authData,
|
|
805
933
|
timezone,
|
|
806
934
|
zcacheTestObj,
|
|
807
935
|
cursorTestObj,
|
|
936
|
+
appId,
|
|
937
|
+
deployKey,
|
|
808
938
|
);
|
|
809
939
|
}
|
|
810
940
|
}
|
|
@@ -814,11 +944,14 @@ class InvokeCommand extends BaseCommand {
|
|
|
814
944
|
actionTypePlural,
|
|
815
945
|
action,
|
|
816
946
|
inputData,
|
|
947
|
+
authId,
|
|
817
948
|
authData,
|
|
818
949
|
meta,
|
|
819
950
|
timezone,
|
|
820
951
|
zcacheTestObj,
|
|
821
952
|
cursorTestObj,
|
|
953
|
+
appId,
|
|
954
|
+
deployKey,
|
|
822
955
|
) {
|
|
823
956
|
// Do these in order:
|
|
824
957
|
// 1. Prompt for static input fields that alter dynamic fields
|
|
@@ -835,17 +968,20 @@ class InvokeCommand extends BaseCommand {
|
|
|
835
968
|
inputData,
|
|
836
969
|
staticInputFields,
|
|
837
970
|
appDefinition,
|
|
971
|
+
authId,
|
|
838
972
|
authData,
|
|
839
973
|
meta,
|
|
840
974
|
timezone,
|
|
841
975
|
zcacheTestObj,
|
|
842
976
|
cursorTestObj,
|
|
977
|
+
appId,
|
|
978
|
+
deployKey,
|
|
843
979
|
);
|
|
844
980
|
|
|
845
981
|
let methodName = `${actionTypePlural}.${action.key}.operation.inputFields`;
|
|
846
982
|
startSpinner(`Invoking ${methodName}`);
|
|
847
983
|
|
|
848
|
-
const inputFields = await
|
|
984
|
+
const inputFields = await localAppCommandWithRelayErrorHandler({
|
|
849
985
|
command: 'execute',
|
|
850
986
|
method: methodName,
|
|
851
987
|
bundle: {
|
|
@@ -857,6 +993,9 @@ class InvokeCommand extends BaseCommand {
|
|
|
857
993
|
cursorTestObj,
|
|
858
994
|
customLogger,
|
|
859
995
|
calledFromCliInvoke: true,
|
|
996
|
+
appId,
|
|
997
|
+
deployKey,
|
|
998
|
+
relayAuthenticationId: authId,
|
|
860
999
|
});
|
|
861
1000
|
endSpinner();
|
|
862
1001
|
|
|
@@ -867,11 +1006,14 @@ class InvokeCommand extends BaseCommand {
|
|
|
867
1006
|
inputData,
|
|
868
1007
|
inputFields,
|
|
869
1008
|
appDefinition,
|
|
1009
|
+
authId,
|
|
870
1010
|
authData,
|
|
871
1011
|
meta,
|
|
872
1012
|
timezone,
|
|
873
1013
|
zcacheTestObj,
|
|
874
1014
|
cursorTestObj,
|
|
1015
|
+
appId,
|
|
1016
|
+
deployKey,
|
|
875
1017
|
);
|
|
876
1018
|
}
|
|
877
1019
|
|
|
@@ -879,7 +1021,7 @@ class InvokeCommand extends BaseCommand {
|
|
|
879
1021
|
methodName = `${actionTypePlural}.${action.key}.operation.perform`;
|
|
880
1022
|
|
|
881
1023
|
startSpinner(`Invoking ${methodName}`);
|
|
882
|
-
const output = await
|
|
1024
|
+
const output = await localAppCommandWithRelayErrorHandler({
|
|
883
1025
|
command: 'execute',
|
|
884
1026
|
method: methodName,
|
|
885
1027
|
bundle: {
|
|
@@ -891,15 +1033,40 @@ class InvokeCommand extends BaseCommand {
|
|
|
891
1033
|
cursorTestObj,
|
|
892
1034
|
customLogger,
|
|
893
1035
|
calledFromCliInvoke: true,
|
|
1036
|
+
appId,
|
|
1037
|
+
deployKey,
|
|
1038
|
+
relayAuthenticationId: authId,
|
|
894
1039
|
});
|
|
895
1040
|
endSpinner();
|
|
896
1041
|
|
|
897
1042
|
return output;
|
|
898
1043
|
}
|
|
899
1044
|
|
|
1045
|
+
async promptForAuthentication() {
|
|
1046
|
+
const auths = (await listAuthentications()).authentications;
|
|
1047
|
+
if (!auths || auths.length === 0) {
|
|
1048
|
+
throw new Error(
|
|
1049
|
+
'No authentications/connections found for your integration. ' +
|
|
1050
|
+
'Add a new connection at https://zapier.com/app/assets/connections ' +
|
|
1051
|
+
'or use local auth data by removing the `--authentication-id` flag.',
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
const authChoices = auths.map((auth) => ({
|
|
1055
|
+
name: `${auth.title} | ${auth.app_version} | ID: ${auth.id}`,
|
|
1056
|
+
value: auth.id,
|
|
1057
|
+
}));
|
|
1058
|
+
return this.promptWithList(
|
|
1059
|
+
'Which authentication/connection would you like to use?',
|
|
1060
|
+
authChoices,
|
|
1061
|
+
{ useStderr: true },
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
900
1065
|
async perform() {
|
|
1066
|
+
let authId = this.flags['authentication-id'];
|
|
1067
|
+
|
|
901
1068
|
const dotenvResult = dotenv.config({ override: true });
|
|
902
|
-
if (_.isEmpty(dotenvResult.parsed)) {
|
|
1069
|
+
if (!authId && _.isEmpty(dotenvResult.parsed)) {
|
|
903
1070
|
console.warn(
|
|
904
1071
|
'The .env file does not exist or is empty. ' +
|
|
905
1072
|
'You may need to set some environment variables in there if your code uses process.env.',
|
|
@@ -955,10 +1122,37 @@ class InvokeCommand extends BaseCommand {
|
|
|
955
1122
|
}
|
|
956
1123
|
}
|
|
957
1124
|
|
|
958
|
-
const
|
|
1125
|
+
const appId = (await getLinkedAppConfig(null, false))?.id;
|
|
1126
|
+
const deployKey = (await readCredentials(false))[AUTH_KEY];
|
|
1127
|
+
|
|
1128
|
+
if (authId === '-' || authId === '') {
|
|
1129
|
+
if (this.nonInteractive) {
|
|
1130
|
+
throw new Error(
|
|
1131
|
+
"You cannot specify '-' or an empty string for `--authentication-id` in non-interactive mode.",
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
authId = (await this.promptForAuthentication()).toString();
|
|
1135
|
+
}
|
|
1136
|
+
|
|
959
1137
|
const zcacheTestObj = {};
|
|
960
1138
|
const cursorTestObj = {};
|
|
961
1139
|
|
|
1140
|
+
let authData = {};
|
|
1141
|
+
if (authId) {
|
|
1142
|
+
// Fill authData with curlies if we're in relay mode
|
|
1143
|
+
const authFields = appDefinition.authentication.fields || [];
|
|
1144
|
+
for (const field of authFields) {
|
|
1145
|
+
if (field.key) {
|
|
1146
|
+
authData[field.key] = `{{${field.key}}}`;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// Load from .env as well even in relay mode, in case the integration code
|
|
1152
|
+
// assumes there are values in bundle.authData. Loading from .env at least
|
|
1153
|
+
// gives the developer an option to override the values in bundle.authData.
|
|
1154
|
+
authData = { ...authData, ...loadAuthDataFromEnv() };
|
|
1155
|
+
|
|
962
1156
|
if (actionType === 'auth') {
|
|
963
1157
|
const meta = {
|
|
964
1158
|
isLoadingSample: false,
|
|
@@ -970,6 +1164,13 @@ class InvokeCommand extends BaseCommand {
|
|
|
970
1164
|
};
|
|
971
1165
|
switch (actionKey) {
|
|
972
1166
|
case 'start': {
|
|
1167
|
+
if (authId) {
|
|
1168
|
+
throw new Error(
|
|
1169
|
+
'The `--authentication-id` flag is not applicable. ' +
|
|
1170
|
+
'The `auth start` subcommand is to initialize local auth data in the .env file, ' +
|
|
1171
|
+
'whereas `--authentication-id` is for proxying requests using production auth data.',
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
973
1174
|
const newAuthData = await this.startAuth(
|
|
974
1175
|
appDefinition,
|
|
975
1176
|
zcacheTestObj,
|
|
@@ -984,6 +1185,13 @@ class InvokeCommand extends BaseCommand {
|
|
|
984
1185
|
return;
|
|
985
1186
|
}
|
|
986
1187
|
case 'refresh': {
|
|
1188
|
+
if (authId) {
|
|
1189
|
+
throw new Error(
|
|
1190
|
+
'The `--authentication-id` flag is not applicable. ' +
|
|
1191
|
+
'The `auth refresh` subcommand can only refresh your local auth data in the .env file. ' +
|
|
1192
|
+
'You might want to run `auth test` instead, which tests and may refresh auth data with the specified authentication ID in production.',
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
987
1195
|
const newAuthData = await this.refreshAuth(
|
|
988
1196
|
appDefinition,
|
|
989
1197
|
authData,
|
|
@@ -999,7 +1207,14 @@ class InvokeCommand extends BaseCommand {
|
|
|
999
1207
|
return;
|
|
1000
1208
|
}
|
|
1001
1209
|
case 'test': {
|
|
1002
|
-
const output = await testAuth(
|
|
1210
|
+
const output = await testAuth(
|
|
1211
|
+
authId,
|
|
1212
|
+
authData,
|
|
1213
|
+
meta,
|
|
1214
|
+
zcacheTestObj,
|
|
1215
|
+
appId,
|
|
1216
|
+
deployKey,
|
|
1217
|
+
);
|
|
1003
1218
|
console.log(JSON.stringify(output, null, 2));
|
|
1004
1219
|
return;
|
|
1005
1220
|
}
|
|
@@ -1009,14 +1224,24 @@ class InvokeCommand extends BaseCommand {
|
|
|
1009
1224
|
console.warn(
|
|
1010
1225
|
'Function-based connection label is not supported yet. Printing auth test result instead.',
|
|
1011
1226
|
);
|
|
1012
|
-
const output = await testAuth(
|
|
1227
|
+
const output = await testAuth(
|
|
1228
|
+
authId,
|
|
1229
|
+
authData,
|
|
1230
|
+
meta,
|
|
1231
|
+
zcacheTestObj,
|
|
1232
|
+
appId,
|
|
1233
|
+
deployKey,
|
|
1234
|
+
);
|
|
1013
1235
|
console.log(JSON.stringify(output, null, 2));
|
|
1014
1236
|
} else {
|
|
1015
1237
|
const output = await getAuthLabel(
|
|
1016
1238
|
labelTemplate,
|
|
1239
|
+
authId,
|
|
1017
1240
|
authData,
|
|
1018
1241
|
meta,
|
|
1019
1242
|
zcacheTestObj,
|
|
1243
|
+
appId,
|
|
1244
|
+
deployKey,
|
|
1020
1245
|
);
|
|
1021
1246
|
if (output) {
|
|
1022
1247
|
console.log(output);
|
|
@@ -1085,11 +1310,14 @@ class InvokeCommand extends BaseCommand {
|
|
|
1085
1310
|
actionTypePlural,
|
|
1086
1311
|
action,
|
|
1087
1312
|
inputData,
|
|
1313
|
+
authId,
|
|
1088
1314
|
authData,
|
|
1089
1315
|
meta,
|
|
1090
1316
|
timezone,
|
|
1091
1317
|
zcacheTestObj,
|
|
1092
1318
|
cursorTestObj,
|
|
1319
|
+
appId,
|
|
1320
|
+
deployKey,
|
|
1093
1321
|
);
|
|
1094
1322
|
console.log(JSON.stringify(output, null, 2));
|
|
1095
1323
|
}
|
|
@@ -1149,6 +1377,11 @@ InvokeCommand.flags = buildFlags({
|
|
|
1149
1377
|
'Only used by `auth start` subcommand. The local port that will be used to start the local HTTP server to listen for the OAuth2 callback. This port can be different from the one in the redirect URI if you have port forwarding set up.',
|
|
1150
1378
|
default: 9000,
|
|
1151
1379
|
}),
|
|
1380
|
+
'authentication-id': Flags.string({
|
|
1381
|
+
char: 'a',
|
|
1382
|
+
description:
|
|
1383
|
+
'EXPERIMENTAL: Instead of using the local .env file, use the production authentication data with the given authentication ID (aka the "app connection" on Zapier). Find them at https://zapier.com/app/assets/connections (https://zpr.io/z8SjFTdnTFZ2 for instructions) or specify \'-\' to interactively select one from your available authentications. When specified, the code will still run locally, but all outgoing requests will be proxied through Zapier with the production auth data.',
|
|
1384
|
+
}),
|
|
1152
1385
|
},
|
|
1153
1386
|
});
|
|
1154
1387
|
|
|
@@ -1171,13 +1404,27 @@ InvokeCommand.examples = [
|
|
|
1171
1404
|
'zapier invoke auth label',
|
|
1172
1405
|
'zapier invoke trigger new_recipe',
|
|
1173
1406
|
`zapier invoke create add_recipe --inputData '{"title": "Pancakes"}'`,
|
|
1174
|
-
'zapier invoke search find_recipe -i @file.json',
|
|
1407
|
+
'zapier invoke search find_recipe -i @file.json --non-interactive',
|
|
1175
1408
|
'cat file.json | zapier invoke trigger new_recipe -i @-',
|
|
1409
|
+
'zapier invoke search find_ticket --authentication-id 12345',
|
|
1410
|
+
'zapier invoke create add_ticket -a -',
|
|
1176
1411
|
];
|
|
1177
1412
|
InvokeCommand.description = `Invoke an auth operation, a trigger, or a create/search action locally.
|
|
1178
1413
|
|
|
1179
1414
|
This command emulates how Zapier production environment would invoke your integration. It runs code locally, so you can use this command to quickly test your integration without deploying it to Zapier. This is especially useful for debugging and development.
|
|
1180
1415
|
|
|
1416
|
+
Why use this command?
|
|
1417
|
+
|
|
1418
|
+
* Fast feedback loop: Write code and run this command to verify if it works immediately
|
|
1419
|
+
* Step-by-step debugging: Running locally means you can use a debugger to step through your code
|
|
1420
|
+
* Untruncated logs: View complete logs and errors in your terminal
|
|
1421
|
+
|
|
1422
|
+
### Authentication
|
|
1423
|
+
|
|
1424
|
+
You can supply the authentcation data in two ways: Load from the local \`.env\` file or use the (experimental) \`--authentication-id\` flag.
|
|
1425
|
+
|
|
1426
|
+
#### The local \`.env\` file
|
|
1427
|
+
|
|
1181
1428
|
This command loads environment variables and \`authData\` from the \`.env\` file in the current directory. If you don't have a \`.env\` file yet, you can use the \`zapier invoke auth start\` command to help you initialize it, or you can manually create it.
|
|
1182
1429
|
|
|
1183
1430
|
The \`zapier invoke auth start\` subcommand will prompt you for the necessary auth fields and save them to the \`.env\` file. For OAuth2, it will start a local HTTP server, open the authorization URL in the browser, wait for the OAuth2 redirect, and get the access token.
|
|
@@ -1197,6 +1444,19 @@ authData_refresh_token='abcdefg'
|
|
|
1197
1444
|
authData_account_name='zapier'
|
|
1198
1445
|
\`\`\`
|
|
1199
1446
|
|
|
1447
|
+
|
|
1448
|
+
#### The \`--authentication-id\` flag (EXPERIMENTAL)
|
|
1449
|
+
|
|
1450
|
+
Setting up local auth data can be troublesome. You'd have to configure your app server to allow localhost redirect URIs or use a port forwarding tool. This is sometimes not easy to get right.
|
|
1451
|
+
|
|
1452
|
+
The \`--authentication-id\` flag (\`-a\` for short) gives you an alternative (and perhaps easier) way to supply your auth data. You can use \`-a\` to specify an existing production authentication/connection. The available authentications can be found at https://zapier.com/app/assets/connections. Check https://zpr.io/z8SjFTdnTFZ2 for more instructions.
|
|
1453
|
+
|
|
1454
|
+
When \`-a -\` is specified, such as \`zapier invoke auth test -a -\`, the command will interactively prompt you to select one of your available authentications.
|
|
1455
|
+
|
|
1456
|
+
If you know your authentication ID, you can specify it directly, such as \`zapier invoke auth test -a 123456\`.
|
|
1457
|
+
|
|
1458
|
+
#### Testing authentication
|
|
1459
|
+
|
|
1200
1460
|
To test if the auth data is correct, run either one of these:
|
|
1201
1461
|
|
|
1202
1462
|
\`\`\`
|
|
@@ -1204,7 +1464,9 @@ zapier invoke auth test # invokes authentication.test method
|
|
|
1204
1464
|
zapier invoke auth label # invokes authentication.test and renders connection label
|
|
1205
1465
|
\`\`\`
|
|
1206
1466
|
|
|
1207
|
-
To refresh stale auth data for OAuth2 or session auth, run \`zapier invoke auth refresh\`.
|
|
1467
|
+
To refresh stale auth data for OAuth2 or session auth, run \`zapier invoke auth refresh\`. Note that refreshing is only applicable for local auth data in the \`.env\` file.
|
|
1468
|
+
|
|
1469
|
+
### Invoking a trigger or an action
|
|
1208
1470
|
|
|
1209
1471
|
Once you have the correct auth data, you can test an trigger, a search, or a create action. For example, here's how you invoke a trigger with the key \`new_recipe\`:
|
|
1210
1472
|
|
|
@@ -1212,12 +1474,14 @@ Once you have the correct auth data, you can test an trigger, a search, or a cre
|
|
|
1212
1474
|
zapier invoke trigger new_recipe
|
|
1213
1475
|
\`\`\`
|
|
1214
1476
|
|
|
1215
|
-
To add input data, use the \`--inputData\` flag. The input data can come from the command directly, a file, or stdin. See **EXAMPLES** below.
|
|
1477
|
+
To add input data, use the \`--inputData\` flag (\`-i\` for short). The input data can come from the command directly, a file, or stdin. See **EXAMPLES** below.
|
|
1216
1478
|
|
|
1217
1479
|
When you miss any command arguments, such as ACTIONTYPE or ACTIONKEY, the command will prompt you interactively. If you don't want to get interactive prompts, use the \`--non-interactive\` flag.
|
|
1218
1480
|
|
|
1219
1481
|
The \`--debug\` flag will show you the HTTP request logs and any console logs you have in your code.
|
|
1220
1482
|
|
|
1483
|
+
### Limitations
|
|
1484
|
+
|
|
1221
1485
|
The following is a non-exhaustive list of current limitations and may be supported in the future:
|
|
1222
1486
|
|
|
1223
1487
|
- Hook triggers, including REST hook subscribe/unsubscribe
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const BaseCommand = require('../ZapierBaseCommand');
|
|
2
|
+
const { Args, Flags } = require('@oclif/core');
|
|
3
|
+
const { buildFlags } = require('../buildFlags');
|
|
4
|
+
|
|
5
|
+
const { callAPI } = require('../../utils/api');
|
|
6
|
+
|
|
7
|
+
class LegacyCommand extends BaseCommand {
|
|
8
|
+
async perform() {
|
|
9
|
+
const app = await this.getWritableApp();
|
|
10
|
+
const { version } = this.args;
|
|
11
|
+
|
|
12
|
+
if (
|
|
13
|
+
!this.flags.force &&
|
|
14
|
+
!(await this.confirm(
|
|
15
|
+
'Are you sure you want to mark this version as legacy? Existing Zaps and automations will continue to work, but users may not be able to create new Zaps or automations with this version.',
|
|
16
|
+
))
|
|
17
|
+
) {
|
|
18
|
+
this.log('\nCancelled, version is not marked as legacy.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this.log(
|
|
23
|
+
`\nPreparing to mark version ${version} your app "${app.title}" as legacy.\n`,
|
|
24
|
+
);
|
|
25
|
+
const url = `/apps/${app.id}/versions/${version}/legacy`;
|
|
26
|
+
this.startSpinner(`Making ${version} legacy`);
|
|
27
|
+
await callAPI(url, {
|
|
28
|
+
method: 'PUT',
|
|
29
|
+
});
|
|
30
|
+
this.stopSpinner();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
LegacyCommand.flags = buildFlags({
|
|
35
|
+
commandFlags: {
|
|
36
|
+
force: Flags.boolean({
|
|
37
|
+
char: 'f',
|
|
38
|
+
description: 'Skip confirmation prompt. Use with caution.',
|
|
39
|
+
}),
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
LegacyCommand.args = {
|
|
43
|
+
version: Args.string({
|
|
44
|
+
description: 'The version to mark as legacy.',
|
|
45
|
+
required: true,
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
LegacyCommand.examples = ['zapier legacy 1.2.3'];
|
|
49
|
+
LegacyCommand.description = `Mark a non-production version of your integration as legacy.
|
|
50
|
+
|
|
51
|
+
Use this when an integration version is no longer recommended for new users, but you don't want to block existing users from using it.
|
|
52
|
+
|
|
53
|
+
Reasons why you might want to mark a version as legacy:
|
|
54
|
+
- this version may be discontinued in the future
|
|
55
|
+
- this version has bugs
|
|
56
|
+
- a newer version has been released and you want to encourage users to upgrade
|
|
57
|
+
|
|
58
|
+
`;
|
|
59
|
+
LegacyCommand.skipValidInstallCheck = true;
|
|
60
|
+
|
|
61
|
+
module.exports = LegacyCommand;
|
|
@@ -258,11 +258,6 @@ ${metadataPromptHelper}`);
|
|
|
258
258
|
|
|
259
259
|
this.stopSpinner();
|
|
260
260
|
this.log(' Promotion successful!');
|
|
261
|
-
if (!this.flags.invokedFromAnotherCommand) {
|
|
262
|
-
this.log(
|
|
263
|
-
'Optionally, run the `zapier migrate` command to move users to this version.',
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
261
|
}
|
|
267
262
|
}
|
|
268
263
|
|