Compare commits
2503 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dfb00e84e9 | |||
| b5a64545bb | |||
| 3cf3eaff48 | |||
| 4ca758a3de | |||
| da81537009 | |||
| 7c1b13ba3b | |||
| 4b654e5b3b | |||
| 726a50ace7 | |||
| 9deffb67c4 | |||
| ff04bf44ee | |||
| e740297829 | |||
| a31705e198 | |||
| f0bdf53364 | |||
| 9638499163 | |||
| 9104c252b7 | |||
| 72cf345602 | |||
| d5b8f8299d | |||
| dd22b88d25 | |||
| 62b9c5879c | |||
| 1b0973fbc1 | |||
| fc78854ed4 | |||
| ed15bb0618 | |||
| ced9034428 | |||
| 7ec329d5d6 | |||
| 81180999de | |||
| feaa79ecf3 | |||
| d34dc0847c | |||
| 1b7c7520b4 | |||
| 34d77e830c | |||
| 87c302bf26 | |||
| d462c901f5 | |||
| 55c3d79cc8 | |||
| ce901c92e4 | |||
| 0fd409c6dc | |||
| f4e7379768 | |||
| ee99191fb4 | |||
| 18124ae32a | |||
| de3373b8f9 | |||
| bdb4e6e2bd | |||
| 0a790de2c1 | |||
| ffb55bfde6 | |||
| c0fbe56f79 | |||
| 342ab0d471 | |||
| aa9fe7d408 | |||
| f499c10f09 | |||
| 45ed7cdf38 | |||
| fa271aaed2 | |||
| 8883476dcb | |||
| c1755ff85b | |||
| 6d04f6c62a | |||
| 53363711bb | |||
| 442ee45e97 | |||
| 8405b337f9 | |||
| facae926ce | |||
| 9544624e00 | |||
| a489fd465f | |||
| 9ff4c0dbd5 | |||
| 36ec16babe | |||
| 92233f2e90 | |||
| efd590976c | |||
| 463cbed7df | |||
| 9138976dad | |||
| ace4d5f6ce | |||
| b09ecb0b06 | |||
| 10fef0f667 | |||
| 3e5945fb9e | |||
| fdf1b2148c | |||
| 7e4d72f959 | |||
| 3e203ea967 | |||
| af56598a58 | |||
| 1fef1fa5f8 | |||
| bd2f68a51d | |||
| 64477f6b3a | |||
| 8b09dfd697 | |||
| f330673143 | |||
| 9351c05126 | |||
| af722e54d8 | |||
| 1eb89844f4 | |||
| 004423aea3 | |||
| 369c6245ab | |||
| b8ae937966 | |||
| 3b510a4f3d | |||
| b3e609d53d | |||
| 2f07a792e9 | |||
| 078bf2bc9c | |||
| a7c8f0b90e | |||
| 495acf4319 | |||
| dce86119d4 | |||
| 2c70b7a360 | |||
| c518185947 | |||
| b314178de2 | |||
| e0a2cec978 | |||
| d3608be1a0 | |||
| 4c79129242 | |||
| 8ac83f1d59 | |||
| 17e6d42989 | |||
| 0a3bbc1caf | |||
| 89e1331e49 | |||
| d934a53e6d | |||
| 2398d60b1a | |||
| 1bd755b628 | |||
| 861d5fa1b9 | |||
| 0239fc6773 | |||
| de57592d79 | |||
| f70f3a0a5d | |||
| 6c96b331dd | |||
| 767e09ee18 | |||
| b2f3ade7c7 | |||
| 8f050b40c1 | |||
| 3cf01ff14c | |||
| 73e0084125 | |||
| 093c9ec015 | |||
| 475dddfbe4 | |||
| 188e4f2740 | |||
| 4dc2b3184b | |||
| 139d541d86 | |||
| 10798c0a05 | |||
| 9c6ad11479 | |||
| 5527ef17f4 | |||
| 981f4010a9 | |||
| db7e8923c0 | |||
| 0eef5c2f01 | |||
| 08901f2e8a | |||
| 51b365226d | |||
| 0b89ee7eb5 | |||
| d7c4b24203 | |||
| d7352867ec | |||
| a2b97bd918 | |||
| 5991a767f7 | |||
| 643eba263e | |||
| 4db8a3992b | |||
| 03f7156749 | |||
| d9912e5548 | |||
| 3c85c985d9 | |||
| 0cf848b9b9 | |||
| ef4056abde | |||
| 3a6c25d42d | |||
| 642c95027c | |||
| 8a66a5c6c7 | |||
| 7dcc55a083 | |||
| 6989fec9d0 | |||
| bba190e4e9 | |||
| 6f670c8cc6 | |||
| d8626c624f | |||
| 454ad25b1d | |||
| 4dce703b20 | |||
| ce1e911c90 | |||
| f84f4dcee6 | |||
| bfa3757ee0 | |||
| 1fea5d7af3 | |||
| dd33bbf6a8 | |||
| 74640b1a82 | |||
| 51e6a74eda | |||
| 27a9812194 | |||
| ba03a9ed20 | |||
| f5c1c62a09 | |||
| 420e719db2 | |||
| c448f53964 | |||
| 72230f67d8 | |||
| 4bdc28d7fc | |||
| eb5195768b | |||
| 5b6539d799 | |||
| b1b471cf63 | |||
| bcd80463f3 | |||
| e2781cb090 | |||
| 09f906f7a1 | |||
| 706ab20ced | |||
| 1dde615686 | |||
| dda8be1fd0 | |||
| 2888877463 | |||
| ac4253a187 | |||
| a6f79d77d1 | |||
| 4ca841a1d5 | |||
| 4d2a8728be | |||
| ae3afdfc7e | |||
| e135b06e2c | |||
| 106843be09 | |||
| 022021dc4b | |||
| 8815b1608e | |||
| 3dcd7743be | |||
| 66fd838085 | |||
| b04852c98c | |||
| ad19bfa283 | |||
| ee86910caa | |||
| 9a4daaf024 | |||
| fcf1202af3 | |||
| 43c402ccae | |||
| 24334a1e78 | |||
| 37e27510de | |||
| fe35e8ea39 | |||
| db49879584 | |||
| df68305f28 | |||
| 078b10ccea | |||
| 1f8a36efb4 | |||
| b0c386ff87 | |||
| 8b69e06f79 | |||
| 24aa4c7406 | |||
| 621c45aaf1 | |||
| 9f67b83bc5 | |||
| da7dfd4bca | |||
| 07250f4ace | |||
| 8b5055d9d3 | |||
| ec36918061 | |||
| c895722ffc | |||
| 7df34db36b | |||
| 3008909f02 | |||
| 8af381729c | |||
| 8ca0aeb1bd | |||
| 99f8ec935b | |||
| d07cfe8fdb | |||
| 2f1b2a32c3 | |||
| b6fd62eb54 | |||
| 1dfe7e0ab5 | |||
| 17c7e9765e | |||
| 0ae03477df | |||
| 2348e95b6c | |||
| 439ecf4a7f | |||
| 68750da731 | |||
| 61de39712a | |||
| d32e6f9839 | |||
| 0cda4621c7 | |||
| 4bcd654e49 | |||
| bf0a0a17a0 | |||
| ca59b6b236 | |||
| 2a6cd98d4e | |||
| d4da2f322b | |||
| 04ce02bb5d | |||
| 62e3bb93c1 | |||
| 7da6b94daf | |||
| e95bd3b6fe | |||
| 8e4c70468d | |||
| 1ea5082314 | |||
| 267cbc751c | |||
| 5e522e1f3e | |||
| ba7ef25bcb | |||
| e132ea33f2 | |||
| d0b19d50e4 | |||
| 226ded6156 | |||
| 8f5abfd0a6 | |||
| 1bf2802b67 | |||
| b95826840a | |||
| 584e2b3ffb | |||
| 69af845ad1 | |||
| fba8eec319 | |||
| 01c0f9b324 | |||
| 86e8ccbbd6 | |||
| 0b45338300 | |||
| eafe6a0d7b | |||
| 3fb41f68fb | |||
| f5c819a489 | |||
| 5336317dbb | |||
| 6099e06a71 | |||
| 0066971b77 | |||
| c417a7f9ab | |||
| 1961b994d7 | |||
| 5288ca3840 | |||
| f985dc93aa | |||
| d6e43c40c9 | |||
| 184c24cace | |||
| 9861cb9aa7 | |||
| 2d722b94bd | |||
| 2db67e3b4d | |||
| 6290232858 | |||
| 7f6bf992a2 | |||
| 1f5bd8d6bb | |||
| 46383e57d2 | |||
| 2611b2c171 | |||
| 229207c8f8 | |||
| 2eb0b3abce | |||
| 8b6909b486 | |||
| dbb9fe44d8 | |||
| bb11001fb7 | |||
| b35457bb53 | |||
| 1ea0d39fa2 | |||
| 9193b3c90b | |||
| c349b50164 | |||
| fe3bc6efe4 | |||
| df138ee96e | |||
| d0b8e560c9 | |||
| 537409cec1 | |||
| bac8ad1040 | |||
| cc26cbeb7b | |||
| 3b6c2bd0e8 | |||
| 0b004fbcaf | |||
| c72c21e2a9 | |||
| d6310a79fa | |||
| 953354f367 | |||
| f8ddb21510 | |||
| 761e89108b | |||
| ec34a84d6d | |||
| 9cb5e6847b | |||
| 43f0c6f7f2 | |||
| ffcad81498 | |||
| f16a337c50 | |||
| 30e5303c36 | |||
| 19d5cb596f | |||
| ff58925606 | |||
| 12b16a0030 | |||
| b08c10a716 | |||
| b878561f65 | |||
| 5e36ad961f | |||
| 3dc2f0cfff | |||
| 073c4fb76e | |||
| cef0bd172d | |||
| 23eed197ee | |||
| 3f8f76df76 | |||
| b047023d9c | |||
| 420655f231 | |||
| 520ab88a97 | |||
| f96da50e6a | |||
| 1dc42daed4 | |||
| 0a80e2f5ec | |||
| 4661d2019c | |||
| 4e4e7b705d | |||
| bae1b0be72 | |||
| e890ee01a3 | |||
| af4b0757a9 | |||
| 6ef62d82c4 | |||
| 44df509b62 | |||
| 5d3fe2a5ea | |||
| 076e6dce73 | |||
| f745320456 | |||
| 6e64aaa1ee | |||
| 8b68edfc05 | |||
| 0a7bae4dac | |||
| b925a573f3 | |||
| 0012bb21ce | |||
| 3b3ec9fc4a | |||
| 396663d65c | |||
| f275b47755 | |||
| cfb7481d7e | |||
| 57fcce90d9 | |||
| 2c0ea0c108 | |||
| e81317b72c | |||
| 686cf9dc7e | |||
| a9e7cda37d | |||
| eae0b8a95e | |||
| 1b65b1d596 | |||
| d85b1fe2fd | |||
| f00006af1b | |||
| 75a07fe4ef | |||
| 946e429906 | |||
| 2e5a401ff7 | |||
| b8b84d8d16 | |||
| 4373538476 | |||
| af79ea2f72 | |||
| aab859bc20 | |||
| c692c16183 | |||
| cb59808be2 | |||
| 039777bf63 | |||
| 3547ec13c3 | |||
| 3763577451 | |||
| c6618049f2 | |||
| 28d6aa9885 | |||
| 568786e4f6 | |||
| 2aad2d29de | |||
| 400354ee9e | |||
| ea3ba78d1a | |||
| 38614ee526 | |||
| 15ad6bb5f8 | |||
| 15f431ada6 | |||
| 5163acc6ef | |||
| f9297d783a | |||
| c34a02c06f | |||
| 61ed1fb202 | |||
| 87638ba6c5 | |||
| 26b4100bb0 | |||
| 1157c2adf6 | |||
| 8613d3288b | |||
| ab008fbdff | |||
| 0b30197280 | |||
| 89a121f21e | |||
| 045a8c56af | |||
| d83c11db8c | |||
| 7efe14b835 | |||
| 37116aecf9 | |||
| 9a606e8f2a | |||
| b1e65ed500 | |||
| 26f3dbff06 | |||
| 5ee0b188bd | |||
| 4692cd6a55 | |||
| 7ad8c01853 | |||
| bc27b45fd7 | |||
| 94cc28d377 | |||
| 19e80cef3b | |||
| 5397cd3194 | |||
| f01af9c0ec | |||
| a288010d02 | |||
| b9a7a1c32b | |||
| 65b9a0dce5 | |||
| 7464006e19 | |||
| 590d56b7e7 | |||
| c75cb1e87e | |||
| 597b2f4a6f | |||
| 2e84c6bbb2 | |||
| 06c0cd5297 | |||
| 79eab3d62f | |||
| 6527723a0e | |||
| 3d6652f132 | |||
| da5d9779d4 | |||
| 865399e753 | |||
| 960ea6c8dd | |||
| 39ab48f0cb | |||
| 7341b4cf61 | |||
| 28c5acc6af | |||
| 4366eefc66 | |||
| cb95e761c1 | |||
| 7136748463 | |||
| b0cacfd75c | |||
| 81f03dac79 | |||
| e37d1eadcd | |||
| 23fb310374 | |||
| 797a1732d2 | |||
| c405a417e9 | |||
| 808deb1d77 | |||
| 6ac1473ec3 | |||
| 9c183abf4b | |||
| 33c33faae9 | |||
| 4cccbc2039 | |||
| cc061dedf8 | |||
| 402ce2210f | |||
| 329c5c4070 | |||
| 878aeb7a8c | |||
| 3ee396d788 | |||
| 090037602c | |||
| bee77051e7 | |||
| be6741a4a8 | |||
| 3e9b440322 | |||
| dfea5bc77c | |||
| 1eef30e298 | |||
| e5b9a9de3f | |||
| dfedd3a6e8 | |||
| a19845b4ca | |||
| 094f6f5a7a | |||
| fa60edce2b | |||
| ba44652457 | |||
| 931be39912 | |||
| 5048a27acb | |||
| 71fc615b31 | |||
| 20ed4e22ef | |||
| fc2d337a39 | |||
| 31d96f3862 | |||
| 7b43853ec6 | |||
| 40fa913272 | |||
| cdd5482aad | |||
| 4a3fa20ee7 | |||
| d49ed4cd47 | |||
| db3cf77f5b | |||
| c4a08961d6 | |||
| 5ba1643d46 | |||
| d189f425e8 | |||
| 0fe6fb83ac | |||
| f15ae41f48 | |||
| 46a07fc72e | |||
| 83af317739 | |||
| f4db1b2735 | |||
| 6d4922f419 | |||
| 6af098ee8a | |||
| 1dcb2ebcac | |||
| f65cb463cc | |||
| 2b4ce97f8a | |||
| 25abf319ab | |||
| 77807ab42a | |||
| f21990b14f | |||
| 1873d10e95 | |||
| 32ff3f3136 | |||
| 354b0aefb0 | |||
| aaa70a9aab | |||
| 3b90739087 | |||
| acaae993a5 | |||
| a74f0322e2 | |||
| 1a0286f6b0 | |||
| 64182483e2 | |||
| 87a25fba62 | |||
| 12803536fa | |||
| f160b34b34 | |||
| cca7da9da2 | |||
| 01cf5f3bdc | |||
| 33a928a9ea | |||
| c83443a41a | |||
| 374007bffd | |||
| 092382f319 | |||
| 79a0532e1d | |||
| 56c7c8b1ee | |||
| 722fe7b71e | |||
| 759793b2e3 | |||
| 99c6cd0371 | |||
| 9fbc5ab8de | |||
| 75ac2c9961 | |||
| 87330dd863 | |||
| 38fe9302cf | |||
| 33a455c593 | |||
| 37db0ac58d | |||
| 2cbf50b1cc | |||
| e26923eb19 | |||
| 3e63bcfb11 | |||
| 1e1c18c4a1 | |||
| 953e7fc918 | |||
| 8e147dbe0c | |||
| 86dbd5d1dc | |||
| e85ecfacba | |||
| f210532870 | |||
| 6c9ca686cb | |||
| 35b556d4a3 | |||
| c83339404a | |||
| 4172def1a3 | |||
| c99481ea8d | |||
| a11ddf6564 | |||
| 917a70fbe9 | |||
| 486d6818ba | |||
| 807b9d4c45 | |||
| 0013e78b1a | |||
| 9dd46c83fd | |||
| 1eb6bb8aa9 | |||
| 6c86946614 | |||
| 612b016a15 | |||
| be8beacaec | |||
| 4d316c5524 | |||
| 7fee5d6a87 | |||
| 0dd1aa5a5b | |||
| ed65ba4a73 | |||
| d39020370c | |||
| c18ba11819 | |||
| 5fbd7226eb | |||
| c9e27fd586 | |||
| 51b80eb09b | |||
| f409e9f329 | |||
| 304e6aaad5 | |||
| 3c5d02043e | |||
| 63980f63d4 | |||
| facd2b2131 | |||
| 25452588cc | |||
| 195d8c42fc | |||
| fe04b9d32d | |||
| d03b3aeb5f | |||
| 2ee33e70f7 | |||
| e9209629f7 | |||
| fa1e6bf5e6 | |||
| 93c3b10bf7 | |||
| 56cb2e3b07 | |||
| eabfb2457a | |||
| 317ab442ee | |||
| 2b24b36da6 | |||
| 161d59d01d | |||
| 821b75ed26 | |||
| 1f901e68d3 | |||
| 46d94a6a8f | |||
| 44c2146505 | |||
| ec2f1f5931 | |||
| e86c59f4ec | |||
| 6df6813a17 | |||
| f73679e2a6 | |||
| 68b866921a | |||
| 35364d615a | |||
| f64dd2a99c | |||
| a309a75a4d | |||
| c2e2f7cad9 | |||
| f69b92b153 | |||
| f8760fdd6b | |||
| caa4daabe2 | |||
| 67f685af26 | |||
| b2a8b5653f | |||
| 9232f019e1 | |||
| ac371664af | |||
| e4cca81124 | |||
| d76d2b86d2 | |||
| fcd2d6eea2 | |||
| 067064d19c | |||
| 52cdfb98a4 | |||
| 41261afcc4 | |||
| 77f71fdeb7 | |||
| ce0032e7e5 | |||
| c97ca350ad | |||
| 90abcb2cf7 | |||
| 8626172faa | |||
| 44ef97c656 | |||
| 7661fe5309 | |||
| beb02c871d | |||
| 8a47320272 | |||
| 114c8990a3 | |||
| 7e2d48ac6a | |||
| dbb6667889 | |||
| 29a02131d2 | |||
| 5d887f1cfb | |||
| 18f0e73ed4 | |||
| c4c1425c9b | |||
| 00bb3934ad | |||
| 324096e14e | |||
| 9cad2bb308 | |||
| eec537135a | |||
| 53e42d3350 | |||
| e74122977a | |||
| f32c3ebe2c | |||
| d07ac4fef0 | |||
| 183761b01f | |||
| 361ef70ce8 | |||
| 2bac0a4e5b | |||
| b89a68bb9c | |||
| 496dadebbd | |||
| 155a4eecd4 | |||
| 5eec1b6f7b | |||
| e2ce9472cf | |||
| 06f0b69cfb | |||
| 0ae43fde72 | |||
| 32f5b7e5c4 | |||
| e3a804ca64 | |||
| 6a3ee289b3 | |||
| 02a8605fec | |||
| dbd72e6bbf | |||
| d629c95daf | |||
| 04d6e8e7f0 | |||
| 7caf95158d | |||
| 8245448f29 | |||
| 4d85bcd60e | |||
| d8d156adac | |||
| 7d02c84c47 | |||
| a5d70b8c37 | |||
| d42cd9ffac | |||
| 1b19c83998 | |||
| c0be8bef23 | |||
| 90bc2d0b60 | |||
| 1c747f69f5 | |||
| 57914c7488 | |||
| 1939222d31 | |||
| c29f5fab7a | |||
| adb2cda614 | |||
| c462441f9e | |||
| 2681f6897d | |||
| 2322c67aff | |||
| f645663fd8 | |||
| f2f4d4b827 | |||
| 85108cfcb5 | |||
| 308bd355e2 | |||
| 4ab032c717 | |||
| 17a117d1ee | |||
| bc43cc232d | |||
| 94ae9e65f4 | |||
| 2ed7158cf1 | |||
| 9d8a21a3de | |||
| d313eaa742 | |||
| c5d91e7cca | |||
| cc668a1624 | |||
| d17173ec0a | |||
| ebcd886d20 | |||
| 4976bd1889 | |||
| 9da6d92fb3 | |||
| 9dee5429d5 | |||
| ebe90aac5c | |||
| 289d69c79d | |||
| 5bdaf4f662 | |||
| 67f47bc3df | |||
| 67ddd76ff3 | |||
| 95de883879 | |||
| 3227da122e | |||
| ae243c783a | |||
| eb3b7f5146 | |||
| 414439cac9 | |||
| 7dacccb70e | |||
| a5e1d0595e | |||
| 7e8c6e92a2 | |||
| 24542d4e21 | |||
| b975125af5 | |||
| cc8c60605b | |||
| 23adc15ce3 | |||
| 7204aa0c9a | |||
| 6750429cd4 | |||
| cfe0a6cbb8 | |||
| a9f95971e8 | |||
| d7eee844b7 | |||
| 4c52731d16 | |||
| e53447d0bf | |||
| 53ed23ac58 | |||
| 226fb4a349 | |||
| d89632eb9d | |||
| 4621196993 | |||
| 988e753c74 | |||
| aa49b2ca76 | |||
| fdcd2fdb27 | |||
| 62f94206bb | |||
| 7b6647cfd4 | |||
| 73828c5db7 | |||
| e1d942bb3a | |||
| a764cf64b3 | |||
| 018d51993a | |||
| 4ce51291de | |||
| e0cd68787d | |||
| 6601f4c505 | |||
| 6f62f0e2f1 | |||
| c00026e203 | |||
| 38ac365953 | |||
| 7cfb0f7d2d | |||
| bae194f366 | |||
| 398d95528d | |||
| d1b2ee5490 | |||
| d39b9bc060 | |||
| 0c0b7d86ee | |||
| 03c4d9504f | |||
| 0737bfc5fe | |||
| 80b4916094 | |||
| 00845b43b4 | |||
| 83a74808d5 | |||
| 951679cc10 | |||
| 3cd95f06b2 | |||
| de00fa91ae | |||
| 25d4f0b347 | |||
| 413aa28594 | |||
| 29e153bc54 | |||
| 7b1a2f60d0 | |||
| 2302626703 | |||
| 28b3193743 | |||
| 0fdf8d0f6a | |||
| 890c93a820 | |||
| 3bfcde99dc | |||
| d5a8d19b66 | |||
| 7a3a9a6f7c | |||
| a816c52699 | |||
| bdd3157a45 | |||
| 7337e75d1e | |||
| b39f1694c3 | |||
| b3a919293c | |||
| 927eb1d0ba | |||
| b812c6d984 | |||
| 6a768c3f84 | |||
| 83f4e65bc3 | |||
| ad33abe6bc | |||
| 2e1624235c | |||
| 647f09f2f3 | |||
| d0ad2bd38b | |||
| 3ae4e11bbe | |||
| 6f19a3e750 | |||
| e8442eedad | |||
| a606db25f6 | |||
| 82f715bab6 | |||
| 28914b878c | |||
| 3c2f1709cc | |||
| 40ffde33b6 | |||
| 8184c21a80 | |||
| 5c13d0c2df | |||
| fd8fd22bdc | |||
| 31d8669c9d | |||
| 59e1fbf565 | |||
| 80c9bb0317 | |||
| 6c71bad8ef | |||
| 0e82f6287a | |||
| 52aacc1e1d | |||
| 909b4a5432 | |||
| b48b724c01 | |||
| 91ac1567d4 | |||
| c034035aba | |||
| cd852f9563 | |||
| 010ac6e5b6 | |||
| 0a3cf46068 | |||
| 2bbeeb860d | |||
| b74045fe55 | |||
| a940102d83 | |||
| 74e9d5eb3c | |||
| b256d66374 | |||
| 5b23e60b04 | |||
| 4cd71decbc | |||
| 1ba372e2c3 | |||
| d88f8c87f6 | |||
| ff02ab2aa0 | |||
| 38c71bdb3b | |||
| b68ce9695c | |||
| 0d3e7bd996 | |||
| 1e0acf4ce8 | |||
| b9e8e084a8 | |||
| 1701d4253d | |||
| ff60b71321 | |||
| f68439b936 | |||
| a3fe3944b7 | |||
| 9cf44777e1 | |||
| 5206c2c971 | |||
| 294fd10304 | |||
| 32650f8b9a | |||
| c5d96db9a8 | |||
| d04c66006b | |||
| d43529dce9 | |||
| 5ba95f3cbc | |||
| 7381e5b393 | |||
| b62f00dfd7 | |||
| 95787fcc66 | |||
| 4ef76f72dc | |||
| 939f33e791 | |||
| e15ade91d4 | |||
| 0776cc884d | |||
| 0ad09eb11f | |||
| 9e8b37c6cf | |||
| c2839934b4 | |||
| e2e3c3a9b3 | |||
| 9b3f4bc1a3 | |||
| cf9c34950f | |||
| d4a2927279 | |||
| 56172b1e5c | |||
| 7def5437fd | |||
| d21e364f11 | |||
| 7c6440fd9a | |||
| 0b61207ecf | |||
| fff2f40924 | |||
| 2166929fa8 | |||
| 5aa53da864 | |||
| 21d7ff2f74 | |||
| 8bba30e290 | |||
| fd94a32b95 | |||
| 25f9aa8c2d | |||
| 172bb4527c | |||
| 8ad769569c | |||
| 32eba22628 | |||
| 8d4179b5df | |||
| b7385825b6 | |||
| 5a20528cc8 | |||
| 324cf161ec | |||
| 9f84e77f57 | |||
| beaf0a9ecb | |||
| fb308e8038 | |||
| d2d15dae9f | |||
| 977f064157 | |||
| 8d23dd0186 | |||
| 90ae06df2a | |||
| 2cf253a914 | |||
| 9e462cc329 | |||
| 36ae8910b6 | |||
| fe0ed0bc9a | |||
| ec738515b7 | |||
| 287b6c6bc7 | |||
| aad93b9147 | |||
| 31176245bd | |||
| da45c7e2b9 | |||
| 3c73cb3fed | |||
| 275d01421e | |||
| 75edfccc31 | |||
| 1d230d9fed | |||
| 7d87dbf2ed | |||
| 44467331a2 | |||
| 29cbfd4fb3 | |||
| d946408105 | |||
| 6101372ba8 | |||
| 4993860a18 | |||
| 5e29119e83 | |||
| fe14664cfd | |||
| f871817a2f | |||
| 6ccacaa92e | |||
| 24e0f04aca | |||
| f878d499a7 | |||
| c24cd1c02b | |||
| c6028fca44 | |||
| 25daa5b358 | |||
| 0503a2a517 | |||
| 28fd3d9b18 | |||
| 1a9af1dee4 | |||
| ce27de1af6 | |||
| c9d5334a38 | |||
| bd20b7b8e0 | |||
| 52f40c8c26 | |||
| 622dd6aba4 | |||
| 969a6a1f2c | |||
| 08eab9622d | |||
| 107960b67c | |||
| b394f5e43f | |||
| 4d71a5c9d4 | |||
| 59e2216861 | |||
| 2fba5da04e | |||
| efbe2ddbf7 | |||
| 7f353723eb | |||
| a94d50f3cd | |||
| ae66e6f01a | |||
| e4b0b1e305 | |||
| 65ca2560fc | |||
| bdbf04efe9 | |||
| 4b56671d2d | |||
| f2b190b21a | |||
| 4f5cf931be | |||
| 68beefdaf2 | |||
| 4a52fd2edc | |||
| 47fdfb344d | |||
| ebbbc85d7b | |||
| 22ff2c36d9 | |||
| 5db2a1bb84 | |||
| 8a4ae0df20 | |||
| 80c3e48f5c | |||
| a7244032e4 | |||
| 7fc3ff26bc | |||
| 0648d230fc | |||
| 2626608200 | |||
| 081ef45047 | |||
| 9aa9ebc23f | |||
| f664a10024 | |||
| 52beb2f012 | |||
| 149e3c2d84 | |||
| 223965757c | |||
| 27c1d2516b | |||
| 014a97fcdc | |||
| eb85cc5c14 | |||
| b1d49d71ea | |||
| 9a0a6305e7 | |||
| a218bce73b | |||
| c94ca54aff | |||
| 2e8cd805fd | |||
| 1a9bb4ddc5 | |||
| e7f7c0704a | |||
| b5e0fb0e97 | |||
| f555989a5c | |||
| 2e0ea4520c | |||
| 31a9164df1 | |||
| b363a1e60d | |||
| e5714f9047 | |||
| e9b9c77edc | |||
| acd49994bd | |||
| 5264674cda | |||
| 2825925781 | |||
| 083bd7f1cf | |||
| 3f90fe04b4 | |||
| a63a247b22 | |||
| 7bb589b8f7 | |||
| 7c94ea3ec5 | |||
| 5789ae3c73 | |||
| 95fad3deb8 | |||
| 2b5b8d7931 | |||
| 96e0fb81ae | |||
| e5a568f510 | |||
| 8cb3155ea6 | |||
| 52c5d93449 | |||
| 5e3502f589 | |||
| f1fd36d3a1 | |||
| 9f49b7f4c0 | |||
| eca89e538b | |||
| bbac63e162 | |||
| ed3123470a | |||
| 170bda3158 | |||
| b5a8eec650 | |||
| 817b4ed133 | |||
| e4837cea9d | |||
| e1cdeb284f | |||
| f195933cb6 | |||
| 6e1d91b413 | |||
| d4e39de67e | |||
| 4903cfc689 | |||
| 54a8e26c7c | |||
| 4cc9006c8e | |||
| bc6492b1c4 | |||
| afd05f93fc | |||
| e83f5e7cca | |||
| 7b8e02023e | |||
| 3882f531cf | |||
| 0ce58b5c0f | |||
| f36a1c60f4 | |||
| 98fcc5d2d4 | |||
| 6ff2ee23f8 | |||
| e1405b140f | |||
| 04ab709ddd | |||
| 0736c68d77 | |||
| 34ccf345cd | |||
| 605a38d8ab | |||
| c9fd8ccae2 | |||
| 43482b1b96 | |||
| 81912b2530 | |||
| 2db2e7a369 | |||
| 3589d26fb3 | |||
| e5282fb264 | |||
| 61fddbb8af | |||
| e141aa3ff4 | |||
| 2fa1536315 | |||
| 5607dcfae9 | |||
| bd103802f9 | |||
| 0cbf427a58 | |||
| e53cd477f9 | |||
| df61f29a02 | |||
| feda01ab3b | |||
| fb2684c0b3 | |||
| 89e4b80e65 | |||
| d55fe2d100 | |||
| 49a510aaf9 | |||
| 16a5504a32 | |||
| b720c27c2a | |||
| cad3453e32 | |||
| afe0a8a159 | |||
| 2487e815a3 | |||
| 771348dd5e | |||
| 1f76e1228a | |||
| fe782e5ff8 | |||
| b4167a38f2 | |||
| 61459a197f | |||
| 30b6cc646a | |||
| df95d4e29f | |||
| 5090b64e57 | |||
| 12d188d85a | |||
| ab3e45d933 | |||
| 8c979cabd7 | |||
| a617922c1d | |||
| fec7cd65a7 | |||
| 10cfdb2fa2 | |||
| 43a62d8bec | |||
| 7b32b7ecd6 | |||
| 2fcd166d32 | |||
| d8c673157b | |||
| 99316df879 | |||
| 5a4fa3d2b3 | |||
| 71ececd7ce | |||
| 74519c08f0 | |||
| a85f19e016 | |||
| cfe887341d | |||
| eab17c3467 | |||
| 87c598627f | |||
| 30dc840144 | |||
| dd0e2d0bd2 | |||
| bf0da9ccff | |||
| f430bcf54a | |||
| ec4ef9ab7e | |||
| d01432e742 | |||
| cbb3e17e5d | |||
| 618bc927e9 | |||
| 047c4f4baa | |||
| 3aea158edc | |||
| ed3b93493d | |||
| 410efe1192 | |||
| 58473f1cce | |||
| 399c9df1f3 | |||
| cdfb2d1263 | |||
| 9073a60ce6 | |||
| e9295bee2e | |||
| d1321106c2 | |||
| 8d2dec28e8 | |||
| ea426965de | |||
| 86dfeae727 | |||
| 861cd6acee | |||
| e9055f0914 | |||
| 9e4ada241c | |||
| b13fc5cfe8 | |||
| 35641e3af6 | |||
| df86706199 | |||
| 1f3251ceea | |||
| a1917da1b1 | |||
| e9208bdeaa | |||
| 9ad86e6a62 | |||
| a9bcb00d8b | |||
| 1a0b2aeee1 | |||
| 7d45996bf1 | |||
| 594d7f94a2 | |||
| 5252da6abb | |||
| 4fa3b2161f | |||
| 87732f25ba | |||
| a4a0958ba4 | |||
| e2c8b82ed2 | |||
| 8f060f6868 | |||
| 6ae783c03e | |||
| ed1d9d88de | |||
| f6565eb8ea | |||
| a47cdb5a15 | |||
| 6d45c9966e | |||
| 77753aa5d7 | |||
| 9e00992387 | |||
| 2ef99d8383 | |||
| a03912b804 | |||
| d0ffedfef7 | |||
| d68f093c90 | |||
| 2fc948de76 | |||
| 1dc4783459 | |||
| 18a22001bd | |||
| 1e4bf3043c | |||
| ad48f9bb19 | |||
| 0349f949c4 | |||
| 9b2f741df0 | |||
| 0da4b43d25 | |||
| c8f46ed760 | |||
| fb036e0712 | |||
| ed966f0d18 | |||
| 05c4076a5f | |||
| ac054705a1 | |||
| ab66372ebc | |||
| 2ff093e0ff | |||
| 3a13a22f8a | |||
| 24d2739480 | |||
| 7f15cee11a | |||
| c389fdce04 | |||
| e87d926a5a | |||
| 0bbbc91e53 | |||
| d0edb4489c | |||
| 4bff8b98db | |||
| 03d832ddc1 | |||
| ab01ef855b | |||
| 9e2b2d3b42 | |||
| ce749a0f11 | |||
| d0e52f6186 | |||
| 6cc5808139 | |||
| 8a2cd974fd | |||
| 8e189cbf2b | |||
| 83b7eb8163 | |||
| eb8350647e | |||
| 69e0f43326 | |||
| 7c81259d76 | |||
| b1868a7e62 | |||
| 63156f5140 | |||
| 40bf79a5a2 | |||
| 621350e0fc | |||
| b698da85d1 | |||
| 36c1b30910 | |||
| c6b208b577 | |||
| 6940e8c9c1 | |||
| 575875e807 | |||
| 158504b5c9 | |||
| 611505d43c | |||
| 244efd2ae3 | |||
| 7cd2fae578 | |||
| 6fa22bb7e4 | |||
| d0c04275f6 | |||
| d62eaa2e30 | |||
| 09a40b8d36 | |||
| 9eb194bac2 | |||
| 1113cac7ff | |||
| 769068e93c | |||
| 881689e497 | |||
| 1af6530888 | |||
| 003fa52793 | |||
| a54552c451 | |||
| 26c3a84bfd | |||
| be3c060f38 | |||
| 435f67c5ab | |||
| 1ea3f3d755 | |||
| 8a2dde52f8 | |||
| 7622f48c00 | |||
| 4876d76a49 | |||
| 0b05355e25 | |||
| 89690d76b5 | |||
| a9cf074d82 | |||
| 86f46f5162 | |||
| 693abac7fc | |||
| f79d90bfc3 | |||
| bf347aa5d3 | |||
| b2f350f3f7 | |||
| d5f359d59d | |||
| ab4cb6d484 | |||
| 33517b2c0e | |||
| a9193cfe15 | |||
| 10c2870d8a | |||
| 6894965575 | |||
| 8631a8c559 | |||
| a0418c7f5c | |||
| ad86902073 | |||
| c7d274117c | |||
| 67606e7cee | |||
| e0baafeb7d | |||
| 795577ede0 | |||
| 9a4094d115 | |||
| b3ccfeb015 | |||
| bfaf75c8dd | |||
| 35b669eae8 | |||
| 1893afbdbb | |||
| 17430fb921 | |||
| f09d7254a7 | |||
| 4fe10eb8fa | |||
| 562ba869e2 | |||
| bcf5313498 | |||
| 97bf4d00b1 | |||
| 37486dc87e | |||
| 2b15edb75a | |||
| 926a9c7c78 | |||
| 07f146e86d | |||
| cb6d412002 | |||
| d4fcf043ad | |||
| 6947292adf | |||
| 2270fcdc67 | |||
| cff0498646 | |||
| 62c7db3650 | |||
| 3a91f03340 | |||
| 7bcd0b350e | |||
| 99fb735b5b | |||
| 8e25e3f9a0 | |||
| a43512b117 | |||
| da67607eda | |||
| 8e98810682 | |||
| eb1804339c | |||
| f63df323cf | |||
| 468487d815 | |||
| 0ff8f72668 | |||
| 8df7018b4f | |||
| b5cc1b4c6d | |||
| 2b655707e4 | |||
| 853132453e | |||
| a922f28e86 | |||
| 26e4f2b9f7 | |||
| 1030662c93 | |||
| db3de3841f | |||
| 3d9d6982e4 | |||
| d8a5ad7107 | |||
| e9b9bd8ff9 | |||
| 43a94bfa2c | |||
| b75401bc7b | |||
| 1cebf76b85 | |||
| c113e78c33 | |||
| 4abdc51934 | |||
| a7c10e1c80 | |||
| a9bb37416a | |||
| 400836841a | |||
| 81b37f3408 | |||
| 7fa663f1af | |||
| b6b6005c7d | |||
| 4015a4eac7 | |||
| b458316bef | |||
| ec819c66d8 | |||
| c4d678c439 | |||
| 6edbafff47 | |||
| 5439611d83 | |||
| b0f9fe9265 | |||
| f10501b9cc | |||
| 3400d6c9ab | |||
| 8aeead7e5e | |||
| 41d9498999 | |||
| 284f217163 | |||
| b35d5e35fe | |||
| 499ae4213a | |||
| 9f1681a89c | |||
| baeb11d7fb | |||
| c1907d4e00 | |||
| 0a898900bf | |||
| 0258c394b6 | |||
| 9b6991504c | |||
| 18d0de2366 | |||
| 5f6352b123 | |||
| 9a5c8cbbb7 | |||
| 9d7cfb39aa | |||
| f3f65068fa | |||
| c74a456168 | |||
| 5806c687b6 | |||
| 3436a5ec8e | |||
| e6de29a5ab | |||
| 7e2b134991 | |||
| 288a891c8a | |||
| 25fbc80dd7 | |||
| 3e032e4fca | |||
| b391b81209 | |||
| bbd0d9d31f | |||
| b8c09f6784 | |||
| d217535fcd | |||
| f9b106642d | |||
| 1dac117ed3 | |||
| 0392c7c6c6 | |||
| 5ba72a59c4 | |||
| bfdd3bc361 | |||
| e06b4cfc84 | |||
| 0153c4f900 | |||
| 85f74ce761 | |||
| 639c88d3c9 | |||
| 4aac1f9662 | |||
| 38244b8f98 | |||
| 593372a508 | |||
| c24a9695b6 | |||
| f7516db415 | |||
| 3d520a8867 | |||
| 3a152d0d80 | |||
| 787cc20028 | |||
| 6d28e5f7f0 | |||
| e57769d90c | |||
| b65aa5f9cf | |||
| a95e3855c0 | |||
| 50a3868c67 | |||
| 4f3e314063 | |||
| 885aeb542a | |||
| 933e91e45c | |||
| 3b8ea9b712 | |||
| 09e67dfba9 | |||
| a12f464c4a | |||
| 08bd69ddf8 | |||
| 3862cc069c | |||
| cb37705085 | |||
| 06785525eb | |||
| b046e4a110 | |||
| 92fba7b0b8 | |||
| 976c56a6bb | |||
| 50ddfb8a2e | |||
| 84f41eb69f | |||
| bb18f18d22 | |||
| 94d17dd033 | |||
| e340abd386 | |||
| 2231fc23e1 | |||
| f73ecb6898 | |||
| fc33d3e2ca | |||
| 88c249299f | |||
| 224e5e412a | |||
| c6545d5d6f | |||
| e0b1e021ec | |||
| 235dc6cd02 | |||
| 2858d742e1 | |||
| df26167474 | |||
| a11dea6e7f | |||
| 6d705e5db7 | |||
| d636360ec5 | |||
| 3693df7ad2 | |||
| d15b6ac79f | |||
| 786f2e16ef | |||
| 7c5eb6a3a3 | |||
| af258acf3a | |||
| 21e6f8668d | |||
| d123d1cddd | |||
| e4aa66e213 | |||
| 8e8c6641aa | |||
| 9e3b5707cf | |||
| bc1e0bed1d | |||
| 2306650aa5 | |||
| 5136dd6698 | |||
| 50622ff917 | |||
| 1f217ed4a5 | |||
| 8666358722 | |||
| 70b850140d | |||
| 2d411b4924 | |||
| 4a15d0e822 | |||
| 258c027b2d | |||
| 114c23ab09 | |||
| 396206ca03 | |||
| 1412feba15 | |||
| 4b1fcb7ec6 | |||
| e927f5df5e | |||
| f238d6bfb9 | |||
| 2c0f3ac905 | |||
| 7f08400432 | |||
| f16c2ea0cf | |||
| c2d61f1011 | |||
| c458ee780b | |||
| 10674786e2 | |||
| 65aa12de02 | |||
| df29a37c6c | |||
| 6cafe077b4 | |||
| 7a0c33cd49 | |||
| 4b7c16641b | |||
| 5cfd895f0e | |||
| 08e8ccb3f0 | |||
| 973bb8a076 | |||
| efe84d6a0c | |||
| 7823041b4c | |||
| 055b742b66 | |||
| fa0c9015ae | |||
| c6372bfc0b | |||
| a46bb7c2f7 | |||
| 1a010b7f12 | |||
| da7b020dbb | |||
| f88952d8f6 | |||
| 064cbce172 | |||
| a42a1b231e | |||
| e0e618ac1c | |||
| f6ea37381a | |||
| 214546d17a | |||
| e851cefb39 | |||
| 7030acfa77 | |||
| efe23c01a7 | |||
| 45e4bf0b97 | |||
| b679539c0f | |||
| de8421d966 | |||
| 8c6f8c3b01 | |||
| 504682e9bf | |||
| f0090ca7b5 | |||
| fb862123db | |||
| 89981810d1 | |||
| cd916fdca2 | |||
| a3ccb9950f | |||
| 036bb523bd | |||
| b24317bf9b | |||
| 354e3090bf | |||
| 337a0b9cb5 | |||
| 626ee69dea | |||
| bd2727415f | |||
| ec541338b6 | |||
| c4fbd92b49 | |||
| e49a392e8e | |||
| 6374ef5e6d | |||
| c8e3894559 | |||
| f4216b98ec | |||
| 3dfecdf5d2 | |||
| fbcbd456e3 | |||
| 18afbdec46 | |||
| 7db43b91f1 | |||
| 4071a8c280 | |||
| 3b7028618c | |||
| 0715fdaaba | |||
| 888810c5ae | |||
| 5cef31f1bd | |||
| 3d0ae35156 | |||
| a3d03bdb35 | |||
| 5d52b206c4 | |||
| f05a8cd823 | |||
| 664f2e6623 | |||
| 389d6fe9c6 | |||
| d3c767362c | |||
| 2892e3b36f | |||
| b17de99331 | |||
| 9d8557fbed | |||
| 35c3a4e613 | |||
| 00c9da8de9 | |||
| dfc5fec14a | |||
| 85eca607a1 | |||
| 8973001ec8 | |||
| 5a1e7412d2 | |||
| 8095612d30 | |||
| 2259b812a2 | |||
| 5af6549a0f | |||
| 6d3a590ce8 | |||
| ce5be558e3 | |||
| eb6f1dadd1 | |||
| 2ed7e9f724 | |||
| ecea028fc0 | |||
| c76a7343f9 | |||
| 1281a5e9aa | |||
| 763d09b952 | |||
| 6d3b96aa20 | |||
| 7f9447f403 | |||
| 37836b938b | |||
| b8605f82a8 | |||
| c81b5931c8 | |||
| 3d4aa61a3d | |||
| 21ee76b6b2 | |||
| c4b65e0b96 | |||
| 11e2d2d0e1 | |||
| 149a849a7e | |||
| 18c4ede771 | |||
| 6c3cb7f5d1 | |||
| 945854c671 | |||
| 52460e5977 | |||
| 60d571198f | |||
| 54f73a5fd5 | |||
| ac6d7d7a7a | |||
| 9c35cae103 | |||
| ae358f9d41 | |||
| 786731b4e1 | |||
| 3af3db6a4a | |||
| 4c889cf6f0 | |||
| 89aa546b42 | |||
| 695c4a928d | |||
| ec24dbeef2 | |||
| 43dc022675 | |||
| b3486a9b7f | |||
| 46c1d2484a | |||
| c9e402be57 | |||
| cfb9fffb47 | |||
| 9a531dd7f6 | |||
| 1f7b581208 | |||
| 7a474d45c6 | |||
| ea04d13a60 | |||
| ec825ebb9d | |||
| a873d6dfca | |||
| fb687f3760 | |||
| f00cf33c3a | |||
| 61a8768f9f | |||
| 07b4a4af73 | |||
| 14e2829635 | |||
| 23d721a5ed | |||
| 8dc78776b3 | |||
| 722b4b8e2d | |||
| 260ed6ed8c | |||
| 4710e31c45 | |||
| a1585dfa17 | |||
| 34dfedd2e0 | |||
| f08c4e2354 | |||
| 482760aeed | |||
| 5814b60370 | |||
| 21c2a7da25 | |||
| d7e32348ee | |||
| e0a824cf40 | |||
| a85509ea80 | |||
| 5193fe0775 | |||
| 6078d15aa1 | |||
| d6622accce | |||
| 9805721498 | |||
| 8f9a5e7009 | |||
| 37bae77faa | |||
| cca8c60fbf | |||
| a30cc3332a | |||
| 77046470ea | |||
| 27c9e63e46 | |||
| ebe1fb516c | |||
| 5fda10806d | |||
| 92a8927162 | |||
| bcbb63f585 | |||
| c67a465e3e | |||
| 83b79610af | |||
| 4fa3ea2491 | |||
| 7a4742a314 | |||
| b24df76fca | |||
| 9e30d7a117 | |||
| 789fab5b96 | |||
| 07fa597755 | |||
| 62dd433de4 | |||
| 713e85347c | |||
| 13c2ba7dcd | |||
| 9b4d4090d7 | |||
| f662e02cb1 | |||
| 35fce5a89d | |||
| 39bbf108a3 | |||
| b1cf4cc042 | |||
| c24faa2e52 | |||
| 777f38a5ee | |||
| a79eb76fa9 | |||
| 22c3584988 | |||
| 85f7ad871d | |||
| bfac524c75 | |||
| 2a93c10828 | |||
| 833c509606 | |||
| 1b010571c9 | |||
| 2765fe12cd | |||
| 6f35b2e17d | |||
| 35261ffc75 | |||
| 60309677fe | |||
| 1f1cf0cb74 | |||
| 0a1d3ed5ef | |||
| ab46981182 | |||
| b0f609dc15 | |||
| 7ee305dfc6 | |||
| 3f51835bea | |||
| 0a7ad96dcc | |||
| 6d7f20b527 | |||
| 8b7d847291 | |||
| c77dfae653 | |||
| 3e87e832c7 | |||
| eb83f941d2 | |||
| b1a6ada443 | |||
| dc3306fb95 | |||
| faaaf253b2 | |||
| 2242ca3bf0 | |||
| 258eda5bdb | |||
| 95ed5bacaa | |||
| a87fd6d4bd | |||
| ea6bb4b467 | |||
| eb5d960f3a | |||
| 844c99ddc7 | |||
| 232b9e97eb | |||
| c288397048 | |||
| 7ec084c1a9 | |||
| b37d2a0ea2 | |||
| 26d537867e | |||
| c98ec1f1a8 | |||
| ed0bc153da | |||
| 7ec4584d71 | |||
| d75ee3a3dd | |||
| ad722f1c8c | |||
| 5ed5e8352d | |||
| 51dd20424c | |||
| 1bba822e20 | |||
| a119e79a49 | |||
| 52f9b16003 | |||
| 44dba712d1 | |||
| e28a3566b6 | |||
| eb4f272d80 | |||
| 3d38b95276 | |||
| 38e0460878 | |||
| d8e29a9fa7 | |||
| fb36b68179 | |||
| e14a2554ad | |||
| b91a6548cb | |||
| ee8aedea73 | |||
| 1fa39c875b | |||
| 06741e14b7 | |||
| 8e1929dbec | |||
| 08abc86201 | |||
| 01a4ff387f | |||
| cb026c51f3 | |||
| 3fdb894296 | |||
| da0290e494 | |||
| 5d081b2ef0 | |||
| b087b5cdee | |||
| cb18ee94bf | |||
| 3142891b6a | |||
| 7191697d70 | |||
| 88f4ac7bc2 | |||
| fd9fc1f471 | |||
| 3f6ee25fc4 | |||
| c7c0f5e7f9 | |||
| 98c8893046 | |||
| d0b8f827aa | |||
| d4eac626ec | |||
| 43ca0b7e2a | |||
| 2d5c2394c8 | |||
| 746e4ae088 | |||
| 1e12366e5a | |||
| 98978a9992 | |||
| d7dcb1bf61 | |||
| 3bece03c7f | |||
| 60fdde1919 | |||
| c42d03a4a6 | |||
| 58a6ef436a | |||
| 3ab542b03f | |||
| 2a760f1f2a | |||
| 0a06e84350 | |||
| f2c07c1a31 | |||
| 829b851588 | |||
| 8f524f8c21 | |||
| 0e2a7313c6 | |||
| 9ab7530070 | |||
| f4833d3c1c | |||
| 6d01f2ab0c | |||
| 6b5ebe79f4 | |||
| 83dece4617 | |||
| 0b66a9ab37 | |||
| 4b50bf777f | |||
| 77a8505098 | |||
| 1da4797835 | |||
| 410b282d38 | |||
| 5d012a483d | |||
| 0feb793ce5 | |||
| 26cccd15f9 | |||
| be4da5661e | |||
| e5717080f2 | |||
| de87d71e63 | |||
| e93ecf4f8d | |||
| dae3edd3cd | |||
| af445a8f6d | |||
| 02d114d6f0 | |||
| 8518531cf4 | |||
| 192aad66b3 | |||
| 872b4a5e4d | |||
| 63a11f3f1b | |||
| 6d1bb15d46 | |||
| aba95aaa04 | |||
| 338c0f0d4e | |||
| fd61a002a9 | |||
| fec7a0c96f | |||
| d06e9194c9 | |||
| f8374783c1 | |||
| 6f3be0138d | |||
| 15e527456d | |||
| 7d7e7ba078 | |||
| 1af020f8b8 | |||
| 79a1f5daea | |||
| cee489025f | |||
| e00a048afc | |||
| 0ecebabd3f | |||
| a9591ca396 | |||
| db6be0f7cb | |||
| 683f24d4e4 | |||
| c4249d9e78 | |||
| e714b69896 | |||
| 378a7e390e | |||
| 96a5ccd715 | |||
| d3be9dc294 | |||
| 3f60917d17 | |||
| 8430820faf | |||
| 7f5151dcf2 | |||
| 8725a80d78 | |||
| fd85667515 | |||
| 16107fa5e6 | |||
| ec727646fe | |||
| a7f4362a8b | |||
| 7c5d97c603 | |||
| f7850c14f9 | |||
| a4813fe141 | |||
| 5e45309b81 | |||
| 5f0cebc879 | |||
| 122020e66b | |||
| c166ca6aa5 | |||
| 7bbe42935e | |||
| decb17c1ab | |||
| 61246dcfb4 | |||
| 9625258394 | |||
| c051aa284a | |||
| b605ecdaaa | |||
| 27d8742829 | |||
| 7cb350e37b | |||
| e400d2f1fb | |||
| 221370ba9e | |||
| a446367514 | |||
| 50e6d37780 | |||
| 4803ad3c9a | |||
| 7db68764ac | |||
| ef48592a73 | |||
| d0dd3d5acf | |||
| 0c74035a8f | |||
| 213012b66e | |||
| 2022d0ba56 | |||
| ae68825306 | |||
| aa575b0d79 | |||
| 4e83ef642d | |||
| e6740b5451 | |||
| 2e0a820518 | |||
| b5e47b7d60 | |||
| 3d328aeaaf | |||
| 952fa6bc9e | |||
| 7d3bc03594 | |||
| 19baf3f04a | |||
| 73d488f97d | |||
| d6d8ca67a8 | |||
| 9a93b0fee7 | |||
| 900eece37d | |||
| 20711ce4b2 | |||
| d9a43dc579 | |||
| f2aac62611 | |||
| 26d2392ac2 | |||
| 64585b3393 | |||
| 58d919efdc | |||
| 5eeb275b32 | |||
| 629ee14b55 | |||
| 113752e3e9 | |||
| 758fad8447 | |||
| 3967befabd | |||
| cbff0baf15 | |||
| b0cccc059a | |||
| c879f48109 | |||
| fce52cee6b | |||
| aedf7e7295 | |||
| c593132663 | |||
| ff7bdd7619 | |||
| c229fa31fc | |||
| 632f76cbb9 | |||
| 5dae509aa9 | |||
| 1b902dabfa | |||
| a1043a3b28 | |||
| 22c682bf4c | |||
| 0b67b51ae4 | |||
| 1673d4527a | |||
| 5e762a9cbf | |||
| 406be0107e | |||
| 4ab4174cb2 | |||
| 78e6ed9bfc | |||
| f813e59b0c | |||
| 2992a855f9 | |||
| f172a0ee1a | |||
| 3c74e4f5f6 | |||
| bf4eefe4fd | |||
| 2e81d6fe20 | |||
| 77f243a14a | |||
| 4245c21248 | |||
| e6d276de03 | |||
| 3c09c1704d | |||
| 0e3c3a78d7 | |||
| fa28005f40 | |||
| 3a956c2718 | |||
| a21e9e9838 | |||
| c109a9f31c | |||
| c1dd5e92fe | |||
| 441183975c | |||
| 0f9c0a8d06 | |||
| 5beba8f12e | |||
| 9b7102605f | |||
| 0618cd0d7a | |||
| bc7f11fb57 | |||
| 19d731eebb | |||
| e2b183bd96 | |||
| 80709c5415 | |||
| 22e3c7f5f2 | |||
| 843231c410 | |||
| 1a33bdd3ae | |||
| c0300c6bec | |||
| bffa5ef0e2 | |||
| 4e95232d59 | |||
| ca64356f12 | |||
| c2c1b0feb4 | |||
| 57afaf1995 | |||
| 4c965ed5a2 | |||
| 0462141e1b | |||
| ce39397c57 | |||
| 55cb81f7af | |||
| f7a4e69025 | |||
| 55ac0019b7 | |||
| b87a3dd2ba | |||
| 41c751c081 | |||
| 1f34a22bd8 | |||
| 10ef03eee0 | |||
| bef6de13db | |||
| bd356663cc | |||
| 1670c3e19b | |||
| aa35555356 | |||
| 1520be20c4 | |||
| 9cd49a40d5 | |||
| d27f11e26c | |||
| 9aff64183b | |||
| 5e32c8498b | |||
| bd2f2d442d | |||
| 328ff206d7 | |||
| 774a0fe9e3 | |||
| 3eb76739cc | |||
| f00f6ae1bd | |||
| 7798c0166d | |||
| 9c63687d56 | |||
| 28cad34c5f | |||
| 86d345bffc | |||
| 9cdab61eaf | |||
| 48b35c47b4 | |||
| 349d7f38cc | |||
| 7cbc279407 | |||
| 301d500c3d | |||
| 4150ba8786 | |||
| f39bc44eec | |||
| 4fabd481e6 | |||
| a374338ac5 | |||
| a7337478d0 | |||
| a7b37e9f7b | |||
| 48e0cff123 | |||
| 8a4cc312a1 | |||
| f008f803b8 | |||
| b43224c353 | |||
| 8bb9798ff4 | |||
| 86ae6f927a | |||
| c0693ac508 | |||
| ab512157a5 | |||
| 86475d4e3c | |||
| c5084209eb | |||
| eada69040c | |||
| 6deabb21ba | |||
| 2bb324752e | |||
| 174954511e | |||
| 408bd6ddc8 | |||
| 1789d9d215 | |||
| f3ac17ad91 | |||
| 71d78805e7 | |||
| 3012771a21 | |||
| 5ec7198046 | |||
| 60cb8d54c4 | |||
| 9d7186eba5 | |||
| 5401fa1acb | |||
| 79f21fd94e | |||
| fa7ec12434 | |||
| c6a668a5f6 | |||
| dd786845b7 | |||
| 03e90ea48f | |||
| fee24168aa | |||
| b344dfaaf8 | |||
| ce019c7b96 | |||
| 9a52afe1e2 | |||
| d67e429f23 | |||
| 628726459a | |||
| 603c3953c6 | |||
| 8a7795bd4d | |||
| 9202d3458a | |||
| fb98a4708f | |||
| b29039735b | |||
| 4d5303b0ad | |||
| c3f292a320 | |||
| cb414b448e | |||
| 5ad6330868 | |||
| e8ee088f85 | |||
| 167b1d1db9 | |||
| a365b81915 | |||
| 697e8f930a | |||
| 0e0baa8af8 | |||
| a82088c243 | |||
| e4fc05924e | |||
| b3a46212ee | |||
| dec790e4a3 | |||
| a146469d63 | |||
| e5a3bb8903 | |||
| b61b5054dc | |||
| b613f3bbfc | |||
| 800ae1d834 | |||
| d5d3786a97 | |||
| b90eeea1e8 | |||
| aa30013e05 | |||
| eaf06638c3 | |||
| 4834eabb9d | |||
| 8aceb6418a | |||
| da6062a20c | |||
| b57241951b | |||
| 6a1823b242 | |||
| 2ad039f867 | |||
| 634ec6c1e3 | |||
| a73ddb2dad | |||
| 0504667334 | |||
| 6d85eee0cd | |||
| 1f43988ad9 | |||
| 0129cbb162 | |||
| 0121e1b50d | |||
| 63b1c2237a | |||
| c72120eab0 | |||
| 85ced7818f | |||
| 313b7163e8 | |||
| 55eb81f219 | |||
| b0e64937a0 | |||
| 3a2cf0ddb7 | |||
| 0f90ea9455 | |||
| 6d2217bd18 | |||
| 1579cdbfb2 | |||
| f1e81137b7 | |||
| 0f51328979 | |||
| aea812f621 | |||
| 45b2bea39f | |||
| 4f47d03114 | |||
| 618cca3304 | |||
| 4fe573b397 | |||
| d338b95e7e | |||
| 2d9bdb26d4 | |||
| b660a4c07f | |||
| 5706c3ab52 | |||
| e8c81cafb8 | |||
| a0d062c977 | |||
| 87a3bbee8e | |||
| 65aa6e4e4c | |||
| 0432a64357 | |||
| a5ff50f737 | |||
| 763dd8b55a | |||
| c2eea6c2b6 | |||
| 81bbae977f | |||
| 37bd8f4952 | |||
| 20d6c6fdfb | |||
| ebc45b7f8d | |||
| 77f146210a | |||
| 18cb9c6bec | |||
| dfd4966cb0 | |||
| d7384bf481 | |||
| 9e5c687174 | |||
| dcbb0f5287 | |||
| d64cfe5add | |||
| 1fa52f1c8c | |||
| f7dfc712b5 | |||
| 1cfb93ada9 | |||
| ea28f3dd47 | |||
| 2c563ce998 | |||
| 7437d9fbd6 | |||
| 7dd0102579 | |||
| 16c152ec26 | |||
| 01bc7df3e2 | |||
| 92d4008cc2 | |||
| 6d4f71d22c | |||
| 2770df644b | |||
| cc002ef707 | |||
| f552af517b | |||
| 8aff958bd3 | |||
| ad189b1f4b | |||
| 7bebf919e2 | |||
| e54ba7cbed | |||
| 4b6e21d6d4 | |||
| 21d70821de | |||
| a4d3f1b61c | |||
| 42e297474c | |||
| a40afd55d2 | |||
| 621254d0ab | |||
| 0ff568843d | |||
| 1d056b5328 | |||
| cf7c413c87 | |||
| ac87a634a3 | |||
| 1bc9bc9244 | |||
| 2fea9e5a6c | |||
| 2756bfe073 | |||
| 165ca9cb0f | |||
| c9e411be9b | |||
| ee4e181fc3 | |||
| f51f8f3ece | |||
| 840435284b | |||
| 12f4f3bc68 | |||
| 894a5dcb5d | |||
| d65ef5eb87 | |||
| 71007b5f60 | |||
| 3af9b63a9c | |||
| 0932ae7d89 | |||
| 43250c444e | |||
| 12056d888b | |||
| 63e004594c | |||
| ec3e98ca9f | |||
| 0ccc6d3729 | |||
| f3ffffd50b | |||
| e6550d156e | |||
| ae550df37d | |||
| 26ac1fa57c | |||
| 14031a8c6e | |||
| 719ef2a3a9 | |||
| e779cff42a | |||
| 0b3c3758a7 | |||
| ab351cbc8e | |||
| dd4fc8c262 | |||
| a55acb6296 | |||
| aa295134ff | |||
| b2f14cbea3 | |||
| 26e69cb659 | |||
| 51f9bc9d72 | |||
| 74a6a21c35 | |||
| 4cae6fed63 | |||
| b69058bfcb | |||
| 1c5d8a4c0b | |||
| 28c70ab9d1 | |||
| 15ab35c816 | |||
| 1218320492 | |||
| 9d65a1a2c3 | |||
| fc3e85f93e | |||
| 80373c6874 | |||
| 590dd688a9 | |||
| f739f49209 | |||
| dabf26c2c9 | |||
| 8252f3ef86 | |||
| 7d78089275 | |||
| 5ae21f28c3 | |||
| 2614860862 | |||
| 173f88dcad | |||
| c2d8934820 | |||
| 2edff18a59 | |||
| fc94c78109 | |||
| ee20f9212f | |||
| 77a99c226d | |||
| 50921f1307 | |||
| 5445abeb9d | |||
| 566fb54615 | |||
| 100edb8abd | |||
| 160ab22f70 | |||
| 0cf3ebfae3 | |||
| 8cb08b63d2 | |||
| 8767403a44 | |||
| 5f1ac75044 | |||
| 4f21aaef97 | |||
| 8272363069 | |||
| 3e32802fdf | |||
| 3e1c1138e5 | |||
| 7d1e64cb01 | |||
| 08abf25fd9 | |||
| 9c9a4caa20 | |||
| 352b7f75ce | |||
| f0378fa874 | |||
| 8de37d47bf | |||
| 23376457e6 | |||
| 75589d3bae | |||
| 96c4f319e4 | |||
| 8587841ee4 | |||
| 058afb40ce | |||
| dc058c8835 | |||
| f80253ed1d | |||
| 3e384ff18a | |||
| db9b03ca05 | |||
| cc6adecfb4 | |||
| 841421bf76 | |||
| 0f75d15df6 | |||
| f5ebde8ddb | |||
| da9e357b6d | |||
| cde0b7fcfe | |||
| 43f913e796 | |||
| 26ae66ad2a | |||
| 88fe24ad67 | |||
| da0ee481b8 | |||
| ff57a70a53 | |||
| 22ae2131a5 | |||
| 5880d966ac | |||
| 9eeacee7c2 | |||
| 6ced99fb02 | |||
| 28fb5d066f | |||
| 0d72b8e0c4 | |||
| 547aab667d | |||
| d744efdb26 | |||
| 727a492e45 | |||
| 384752d36c | |||
| d699d38981 | |||
| 6b53aeb8c2 | |||
| b7ee8fd432 | |||
| 8836aeae81 | |||
| 2748d9e9a6 | |||
| f2a0f304af | |||
| 7659835541 | |||
| 8862b563dd | |||
| ed1c2da660 | |||
| 9e739a50b2 | |||
| e4efed07e5 | |||
| 55644577ea | |||
| 5df5e30a7d | |||
| 43ceb44db9 | |||
| 154294f86e | |||
| e20f7ba16a | |||
| be6954abf2 | |||
| 810996f26f | |||
| a7044511bb | |||
| 0efbbece9e | |||
| a38945ebcd | |||
| a63ebd73fb | |||
| b34018eb17 | |||
| a6f9e1e35d | |||
| c7c5d407ef | |||
| 0c6d98d353 | |||
| f6ed5517c2 | |||
| 4aae45ede2 | |||
| f969f03197 | |||
| cd8e85f85f | |||
| 3c27b3c40b | |||
| df1f695f9b | |||
| 0a3b12d135 | |||
| aca332fffc | |||
| 350a60590d | |||
| ad8a2f170a | |||
| 67f6971601 | |||
| 695e4ca3f0 | |||
| 4243b10683 | |||
| c9bd1812f4 | |||
| a117a3b534 | |||
| 9e64f9d570 | |||
| 823da44fb7 | |||
| a5a5dcbccb | |||
| e2693eb539 | |||
| 036ffa7e5f | |||
| 679ac99fad | |||
| 9f6886c55b | |||
| ad9089da57 | |||
| 9313adee12 | |||
| 9bb8363643 | |||
| 4e2fe3dcac | |||
| 092b139d71 | |||
| ab92e9515b | |||
| d4939c4e11 | |||
| ef3f075042 | |||
| c76d930f08 | |||
| 06f2fc3aeb | |||
| 3cd4f2fb9f | |||
| 8f011a5da3 | |||
| 067dbfc0cf | |||
| 8dfdfdb2fa | |||
| 3b76574ef8 | |||
| 3a0a6e491c | |||
| 24203d1b8d | |||
| 8da0f9ac01 | |||
| 011264865b | |||
| 889d9910e2 | |||
| 679239d9fc | |||
| 20d8493c3e | |||
| fe598ff713 | |||
| ac1354b71a | |||
| 55f04d5d12 | |||
| 3796ba5b07 | |||
| 86e1e7143f | |||
| d32aa49020 | |||
| 08338d15a5 | |||
| 4b3c9b7230 | |||
| e84e43e4e1 | |||
| 584b12451d | |||
| 0913a34174 | |||
| e6d6bfced4 | |||
| c7e926a8a9 | |||
| 3ad8a0a5de | |||
| 0d918e7bf6 | |||
| 444996533f | |||
| 1b53ccbbac | |||
| dbd4e9a68c | |||
| 0c36c3e16f | |||
| 05af0ba2b5 | |||
| f2e341e753 | |||
| 6e337eb144 | |||
| fd90e3c3d8 | |||
| b969653f7c | |||
| b5128abee0 | |||
| 1f5053bcdb | |||
| 232b58daf1 | |||
| d07a54f09b | |||
| 2adea4cd9b | |||
| 27e1d134f7 | |||
| 92ca01f3c7 | |||
| c75181f10d | |||
| a26002c525 | |||
| 5a3fdc470f | |||
| 781a208c07 | |||
| 67eb592ecc | |||
| 5fa751cd76 | |||
| efc35c6c79 | |||
| 8961a30bf8 | |||
| 65649c1fc7 | |||
| 0fa59d9387 | |||
| aa8cd86041 | |||
| 165bd68d2d | |||
| 9b664a1af2 | |||
| 3d174f5aeb | |||
| b341e7bb71 | |||
| 1dc11a39ea | |||
| 970cfcb094 | |||
| c33e228b26 | |||
| 6ba6e20026 | |||
| 81b2742577 | |||
| ccadf08bd2 | |||
| cea1291496 | |||
| 3e6b0c747b | |||
| affcabc36f | |||
| 6732015b5c | |||
| cbb50a05ad | |||
| 142fa85b14 | |||
| 857ecf1de7 | |||
| df6fe919c2 | |||
| 579e98c7af | |||
| 4724ef00fc | |||
| 77e3769dbd | |||
| 70a547a5c5 | |||
| 3c8a3c421b | |||
| 842ab0cdcc | |||
| 64e0445acb | |||
| 213d86cb1f | |||
| 66805f67fa | |||
| 3defbcc0ed | |||
| 942e695782 | |||
| 4a8b977a99 | |||
| 2e9875c4c6 | |||
| ed775706a0 | |||
| 89abb57e44 | |||
| f264aaa16f | |||
| 2f7caab661 | |||
| c92fec9787 | |||
| 9211cce807 | |||
| 26c4f5d23c | |||
| 4c9891de90 | |||
| 3c706723a2 | |||
| 6e3778d74e | |||
| 8a10431766 | |||
| 825983db77 | |||
| a79ded125e | |||
| e05b3d633d | |||
| f659d9aec6 | |||
| 1772b0664c | |||
| eca961a30f | |||
| c500155d60 | |||
| f8957423e5 | |||
| 9da448a21b | |||
| 8468db0a83 | |||
| f0d3b12d84 | |||
| ce5a42ccd7 | |||
| fc962f50c9 | |||
| 171d16ef41 | |||
| bec76a3704 | |||
| 3c403c4212 | |||
| 97e432462d | |||
| 4a2e0b28f4 | |||
| fb496b1efa | |||
| 6c299072cd | |||
| 25f70c4574 | |||
| 7f0ad4c18a | |||
| 6c50ce078a | |||
| e8d018ef9d | |||
| 9dc2ec4dca | |||
| 694df6ee38 | |||
| c27987c191 | |||
| 19aedf8f73 | |||
| 4c219a8bf8 | |||
| f30037da15 | |||
| df405aa740 | |||
| 7465d31e28 | |||
| 2876946792 | |||
| ae7c1c2cec | |||
| 10b5558dbc | |||
| 570683446c | |||
| 29f3504a23 | |||
| 4bc156ce04 | |||
| c055c97209 | |||
| bc767516b6 | |||
| 7a19bb8381 | |||
| e742486677 | |||
| 821af448f3 | |||
| 9db2e483ef | |||
| 277108d90c | |||
| 49068d8db1 | |||
| 3558a76e27 | |||
| fde3fec37f | |||
| dabb17cf51 | |||
| 7a8ad5f254 | |||
| ab1d283217 | |||
| 7e80c5e7f6 | |||
| c5a5cef9f3 | |||
| f51aa7b792 | |||
| 9175d1e541 | |||
| 38fbf41e79 | |||
| 4bd3cabad4 | |||
| 6c9d31fe1c | |||
| c13c52aa05 | |||
| 260bd5f007 | |||
| 25cf0245a4 | |||
| 98cac166b3 | |||
| c2e9accade | |||
| dc86fc2998 | |||
| 7a6968d0ac | |||
| 2c780c976e | |||
| fbc1b86ea0 | |||
| f20b29519a | |||
| 3c7f6cf9ec | |||
| 1410688499 | |||
| d583e2a8f2 | |||
| a94c8e4576 | |||
| 5fc1236d2e | |||
| 3b67a5ce10 | |||
| 016cf05aba | |||
| 22c8a16758 | |||
| 0955a51333 | |||
| 8dc5bba8ca | |||
| 3538754a76 | |||
| 8ef434eb13 | |||
| 78ecfb60dc | |||
| 2acd79fb36 | |||
| 8d15e9a2b9 | |||
| d99446a1b2 | |||
| 7b24248b80 | |||
| feafa69068 | |||
| 91ed853747 | |||
| 76737caa47 | |||
| b480fa242a | |||
| 192a1d2119 | |||
| 2261a769e4 | |||
| 7e92e8cc75 | |||
| 5a312dec55 | |||
| a1535dff70 | |||
| 4a00abed46 | |||
| 15316a7504 | |||
| 039f652a41 | |||
| fa80ca07b7 | |||
| f2cfa17b62 | |||
| 77124bba78 | |||
| 7530400a38 | |||
| bfd8a4f6b8 | |||
| 4a72aff4ef | |||
| 544b9b94c1 | |||
| 6b05b84342 | |||
| 2ede12c2f3 | |||
| b142c55fc5 | |||
| 454bfcc58e | |||
| eb98f50fca | |||
| 81ddf597ed | |||
| 75d6471c9e | |||
| 68544359f1 | |||
| 187c0279b2 | |||
| 98cf9afd8e | |||
| 3ce5d5bf1a | |||
| f8ac05500a | |||
| 23dbeff1c6 | |||
| ba0a4727d3 | |||
| 54c5c82f22 | |||
| 6a3f26427b | |||
| 9db77b6478 | |||
| 08ecd288e1 | |||
| 10ae5601f8 | |||
| 9386e19620 | |||
| 1df18b386a | |||
| 83201312b2 | |||
| bfa096dc4a | |||
| 81debee7aa | |||
| 02499a0e63 | |||
| 558b705ace | |||
| 803b279133 | |||
| 4874288db0 | |||
| 30c0984623 | |||
| 1b675968f6 | |||
| e58b7ada83 | |||
| a96bfd3528 | |||
| a47a9b4fd6 | |||
| 727ec22fee | |||
| c359962b3a | |||
| 7bc11fe41f | |||
| 7af88c33da | |||
| 108bb6281e | |||
| 88ff526b87 | |||
| b88eaa2c40 | |||
| a46b93e29d | |||
| 1f672d9612 | |||
| d489311371 | |||
| af29669003 | |||
| 8f32446170 | |||
| 7f6e03b776 | |||
| 140d02f462 | |||
| 6a3ffa6395 | |||
| f6363ab5b6 | |||
| 60ac029220 | |||
| 1f3eb459c4 | |||
| 9388b5bbed | |||
| 047b011fdd | |||
| fa470462c4 | |||
| d807421b40 | |||
| b2bd170a2c | |||
| e013c6faa9 | |||
| d60e9ae939 | |||
| 8039f326a9 | |||
| 259e28e13a | |||
| 103f77215c | |||
| 967b8b0053 | |||
| 974033d5d2 | |||
| 84bd5a63a2 | |||
| f0a05ab4e3 | |||
| 805f675264 | |||
| dfab30c901 | |||
| 8f5474072f | |||
| 056bab7233 | |||
| 08c7a04b61 | |||
| f2a96a1535 | |||
| abc113701c | |||
| fb6953bc1d | |||
| 8a6467f4c8 | |||
| 581068362f | |||
| 011d7d5611 | |||
| caac573a64 | |||
| 39d02e6d00 | |||
| 1e1da62b32 | |||
| d67ab54d55 | |||
| 8e5938cd0c | |||
| 16d89c4b79 | |||
| bf9e269ff3 | |||
| a5190693c8 | |||
| de5b2ca3d8 | |||
| 5c8fc8188a | |||
| 5949c98748 | |||
| 4f7a8f6ae0 | |||
| c01bc15622 | |||
| 027f0210dc | |||
| da155d1378 | |||
| 38f32f405f | |||
| 0fee3ceae5 | |||
| 710003ebdf | |||
| 76a2c82d9f | |||
| 1be2af9309 | |||
| cdbae933b2 | |||
| 7f2c9687b7 | |||
| 721a32a379 | |||
| 2424de07ac | |||
| 179afbbcb3 | |||
| 4d6963f0e7 | |||
| 73fb0f3c0d | |||
| 4ed486ef93 | |||
| 9751531cc1 | |||
| 313a8c59cf | |||
| 76c660f167 | |||
| 3d5bbf899e | |||
| 460e8aa4a7 | |||
| 62ab7e098d | |||
| c4a441129b | |||
| 63486d21c4 | |||
| fbdc3c799d | |||
| fc1dd44f39 | |||
| 8a1517bc7f | |||
| fb0ecb8c34 | |||
| c091bc3326 | |||
| c27bdf6308 | |||
| 007dc2d713 | |||
| ba868cbd40 | |||
| 030844d905 | |||
| 36e25a85f8 | |||
| 4b0d03f9cc | |||
| d6c6c71268 | |||
| 6117bcf7eb | |||
| e1fb69fe44 | |||
| bf5621b716 | |||
| 1c9be1ee1d | |||
| a020dfa036 | |||
| 2e28bd09ca | |||
| 6595535b40 | |||
| a7eac27b98 | |||
| b98bae8588 | |||
| 90a582f6ad | |||
| c41c2e8725 | |||
| ed4d6846f7 | |||
| 952e584d68 | |||
| f178629b9d | |||
| eb2741708a | |||
| fce24cc7fa | |||
| 1ca8760868 | |||
| ffcdc763eb | |||
| bacd76c8e5 | |||
| cf04c3902f | |||
| c4ba591df0 | |||
| ef8431b292 | |||
| b2290e3bc0 | |||
| 1bb2ebc7bc | |||
| 0193327f5d | |||
| 431079c894 | |||
| cc6a37bdf6 | |||
| 9539138992 | |||
| dee2db231a | |||
| 5e99b28ea5 | |||
| 038d53c7c5 | |||
| ad1f9346b8 | |||
| ddfce4e3c7 | |||
| 8a73e559e8 | |||
| ad26302925 | |||
| 2a20546e7b | |||
| 137db98176 | |||
| 94154bd96c | |||
| c34a28b2d5 | |||
| 79622b6123 | |||
| d329aca7e5 | |||
| a347e5526f | |||
| 5328ba1556 | |||
| 7d12d3242e | |||
| 706024841a | |||
| 6e5695f873 | |||
| 565aba4021 | |||
| 5a10e53de6 | |||
| c927342da3 | |||
| 862eeb89d5 | |||
| b88ad37b92 | |||
| 5ff4b68bae | |||
| a7107cf1b1 | |||
| 6132cdf8c0 | |||
| d39fb33c70 | |||
| 5e7ff78f23 | |||
| 05289d0cb1 | |||
| 7dbc634388 | |||
| d58add78bf | |||
| 0c8448c65d | |||
| eed039319e | |||
| 3542c0ed87 | |||
| 162c0f5db5 | |||
| 5f649d1b2e | |||
| e261149065 | |||
| 5f3d985b64 | |||
| 283f6d6be6 | |||
| 7d1b4e71a5 | |||
| 29b4ba4c78 | |||
| cab222ac4b | |||
| 667a60a551 | |||
| 710bcc2c47 | |||
| d1d34da9b2 | |||
| 0c476093d7 | |||
| ba2c895e53 | |||
| 764dd21613 | |||
| 78c3e1060d | |||
| 96a180f26e | |||
| 35718033bd | |||
| 5501a927bf | |||
| 17568a0aec | |||
| 563a535b56 | |||
| 2a2652d3aa | |||
| aca9081e64 | |||
| ccd89d08d9 | |||
| bf57430b66 | |||
| ad70dbc5dd | |||
| a5d8290663 | |||
| 4fa967b2b1 | |||
| cd11246d9a | |||
| f377aba208 | |||
| 55a9031526 |
@@ -2,14 +2,10 @@
|
||||
"$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json",
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"fixed": [["@trigger.dev/*"]],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": [
|
||||
"wss",
|
||||
"webapp",
|
||||
"docs"
|
||||
]
|
||||
}
|
||||
"ignore": ["webapp", "emails", "@trigger.dev/database"]
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# You need to stop and re-run docker to switch, `pnpm run docker:db`
|
||||
# To login using GitHub and connect via OAuth with most integrations
|
||||
AUTH_CALLBACK_URL=http://localhost:3004/oauth/callback
|
||||
# To connect with Slack
|
||||
# AUTH_CALLBACK_URL=https://<ngrok subdomain>.eu.ngrok.io/oauth/callback
|
||||
|
||||
# You only need to use this locally if you specify PIZZLY_SECRET_KEY in the webapp .env file
|
||||
# PIZZLY_SECRET_KEY=<secret_key>
|
||||
@@ -3,6 +3,7 @@
|
||||
.github
|
||||
# editor
|
||||
.idea
|
||||
.vscode
|
||||
# dependencies
|
||||
node_modules
|
||||
.pnp
|
||||
@@ -34,4 +35,11 @@ cypress/screenshots
|
||||
cypress/videos
|
||||
|
||||
apps/**/styles/tailwind.css
|
||||
packages/**/styles/tailwind.css
|
||||
packages/**/styles/tailwind.css
|
||||
|
||||
.changeset
|
||||
examples
|
||||
CHANGESETS.md
|
||||
CONTRIBUTING.md
|
||||
README.md
|
||||
LICENSE
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# YOU MIGHT LIKE TO MODIFY THESE VARIABLES
|
||||
SESSION_SECRET=abcdef1234
|
||||
MAGIC_LINK_SECRET=abcdef1234
|
||||
ENCRYPTION_KEY=ae13021afef0819c3a307ad487071c06 # Must be a random 16 byte hex string. You can generate an encryption key by running `openssl rand -hex 16` in your terminal
|
||||
LOGIN_ORIGIN=http://localhost:3030
|
||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres?schema=public
|
||||
REMIX_APP_PORT=3030
|
||||
APP_ENV=development
|
||||
APP_ORIGIN=http://localhost:3030
|
||||
NODE_ENV=development
|
||||
|
||||
# OPTIONAL VARIABLES
|
||||
# This is used for logging in via GitHub. You can leave these commented out if you don't want to use GitHub for authentication.
|
||||
# AUTH_GITHUB_CLIENT_ID=
|
||||
# AUTH_GITHUB_CLIENT_SECRET=
|
||||
|
||||
# Resend is an email service used for signing in to Trigger.dev via a Magic Link.
|
||||
# Emails will print to the console if you leave these commented out
|
||||
### Visit https://resend.com, create an account and get your API key. Then insert it below along with your From and Reply To email addresses. Visit https://resend.com/docs for more information.
|
||||
# RESEND_API_KEY=<api_key>
|
||||
# FROM_EMAIL=
|
||||
# REPLY_TO_EMAIL=
|
||||
|
||||
# CLOUD VARIABLES
|
||||
POSTHOG_PROJECT_KEY=
|
||||
PLAIN_API_KEY=
|
||||
CLOUD_AIRTABLE_CLIENT_ID=
|
||||
CLOUD_AIRTABLE_CLIENT_SECRET=
|
||||
CLOUD_GITHUB_CLIENT_ID=
|
||||
CLOUD_GITHUB_CLIENT_SECRET=
|
||||
CLOUD_SLACK_APP_HOST=
|
||||
CLOUD_SLACK_CLIENT_ID=
|
||||
CLOUD_SLACK_CLIENT_SECRET=
|
||||
@@ -0,0 +1,127 @@
|
||||
name: 🚀 Publish Trigger.dev Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "v.docker.*"
|
||||
paths:
|
||||
- ".github/workflows/publish.yml"
|
||||
- "packages/**"
|
||||
- "!packages/**/*.md"
|
||||
- "!packages/**/*.eslintrc"
|
||||
- "apps/**"
|
||||
- "!apps/**/*.md"
|
||||
- "!apps/**/*.eslintrc"
|
||||
- "integrations/**"
|
||||
- "!integrations/**/*.md"
|
||||
- "!integrations/**/*.eslintrc"
|
||||
- "pnpm-lock.yaml"
|
||||
- "pnpm-workspace.yaml"
|
||||
- "turbo.json"
|
||||
- "docker/Dockerfile"
|
||||
- "docker/scripts/**"
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
packages: write
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
env:
|
||||
AWS_REGION: us-east-1
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
name: ʦ TypeScript
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: ⎔ Setup pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.18
|
||||
|
||||
- name: ⎔ Setup node
|
||||
uses: buildjet/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: 📥 Download deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: 📀 Generate Prisma Client
|
||||
run: pnpm run generate
|
||||
|
||||
- name: 🔎 Type check
|
||||
run: pnpm run typecheck --filter webapp
|
||||
|
||||
publish:
|
||||
needs: [typecheck]
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
outputs:
|
||||
version: ${{ steps.get_version.outputs.version }}
|
||||
short_sha: ${{ steps.get_commit.outputs.sha_short }}
|
||||
steps:
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: 🆚 Get the version
|
||||
id: get_version
|
||||
run: |
|
||||
IMAGE_TAG="${GITHUB_REF#refs/tags/}"
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
if [[ $IMAGE_TAG == v.docker.* ]]; then
|
||||
ORIGINAL_VERSION="${IMAGE_TAG#v.docker.}"
|
||||
IMAGE_TAG="v${ORIGINAL_VERSION}"
|
||||
fi
|
||||
echo "IMAGE_TAG=${IMAGE_TAG}"
|
||||
elif [[ $GITHUB_REF == refs/heads/* ]]; then
|
||||
IMAGE_TAG="${GITHUB_REF#refs/heads/}"
|
||||
echo "IMAGE_TAG=${IMAGE_TAG}"
|
||||
else
|
||||
echo "Invalid reference: ${GITHUB_REF}"
|
||||
exit 1
|
||||
fi
|
||||
echo "::set-output name=version::${IMAGE_TAG}"
|
||||
- name: 🔢 Get the commit hash
|
||||
id: get_commit
|
||||
run: |
|
||||
echo ::set-output name=sha_short::$(echo ${{ github.sha }} | cut -c1-7)
|
||||
|
||||
- name: 🐳 Build Docker Image
|
||||
run: |
|
||||
docker build -t release_build_image -f ./docker/Dockerfile .
|
||||
|
||||
- name: 🐙 Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: 🐙 Push to GitHub Container Registry
|
||||
run: |
|
||||
docker tag release_build_image $REGISTRY/$REPOSITORY:$IMAGE_TAG
|
||||
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
|
||||
env:
|
||||
REGISTRY: ghcr.io/triggerdotdev
|
||||
REPOSITORY: trigger.dev
|
||||
IMAGE_TAG: ${{ steps.get_version.outputs.version }}
|
||||
|
||||
- name: 🐙 Push 'latest' to GitHub Container Registry
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
docker tag release_build_image $REGISTRY/$REPOSITORY:latest
|
||||
docker push $REGISTRY/$REPOSITORY:latest
|
||||
env:
|
||||
REGISTRY: ghcr.io/triggerdotdev
|
||||
REPOSITORY: trigger.dev
|
||||
@@ -0,0 +1,77 @@
|
||||
name: 🦋 Changesets Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".github/workflows/release.yml"
|
||||
- "packages/**"
|
||||
- "!packages/**/*.md"
|
||||
- "changesets/**"
|
||||
- "integrations/**"
|
||||
- "!integrations/**/*.md"
|
||||
- "pnpm-lock.yaml"
|
||||
- "pnpm-workspace.yaml"
|
||||
- "turbo.json"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: 🦋 Changesets Release
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
if: |
|
||||
github.repository == 'triggerdotdev/trigger.dev'
|
||||
outputs:
|
||||
published_packages: ${{ steps.changesets.outputs.publishedPackages }}
|
||||
published: ${{ steps.changesets.outputs.published }}
|
||||
steps:
|
||||
- name: 🛑 Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: ⎔ Setup pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 7.18
|
||||
|
||||
- name: ⎔ Setup node
|
||||
uses: buildjet/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
|
||||
- name: 📥 Download deps
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: 📀 Generate Prisma Client
|
||||
run: pnpm run generate
|
||||
|
||||
- name: 🔎 Type check
|
||||
run: pnpm run typecheck
|
||||
|
||||
- name: 🔐 Setup npm auth
|
||||
run: |
|
||||
echo "registry=https://registry.npmjs.org" >> ~/.npmrc
|
||||
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
|
||||
|
||||
# This action has two responsibilities. The first time the workflow runs
|
||||
# (initial push to the `main` branch) it will create a new branch and
|
||||
# then open a PR with the related changes for the new version. After the
|
||||
# PR is merged, the workflow will run again and this action will build +
|
||||
# publish to npm.
|
||||
- name: 🚀 PR / Publish
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
version: pnpm run changeset:version
|
||||
commit: "chore: Update version for release"
|
||||
title: "chore: Update version for release"
|
||||
publish: pnpm run changeset:release
|
||||
createGithubReleases: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -44,4 +44,8 @@ yarn-error.log*
|
||||
.env
|
||||
.output
|
||||
apps/**/public/build
|
||||
.tests-container-id.txt
|
||||
.tests-container-id.txt
|
||||
.sentryclirc
|
||||
.buildt
|
||||
|
||||
**/tmp/
|
||||
@@ -0,0 +1 @@
|
||||
{ "workspaceId": "63e5e42daf9a537ba8d9503c" }
|
||||
@@ -1 +1,2 @@
|
||||
link-workspace-packages=false
|
||||
link-workspace-packages=false
|
||||
public-hoist-pattern[]=*prisma*
|
||||
@@ -0,0 +1,11 @@
|
||||
node_modules
|
||||
.env
|
||||
.env.local
|
||||
pnpm-lock.yaml
|
||||
tailwind.css
|
||||
.babelrc.json
|
||||
**/.react-email/
|
||||
**/storybook-static/
|
||||
**/.changeset/
|
||||
**/build/
|
||||
**/dist/
|
||||
@@ -17,6 +17,17 @@
|
||||
"name": "Chrome webapp",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}/apps/webapp/app"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Debug Current Test File",
|
||||
"autoAttachChildProcesses": true,
|
||||
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
|
||||
"program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
|
||||
"args": ["run", "${relativeFile}"],
|
||||
"smartStep": true,
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# Warp Launch Configuration
|
||||
#
|
||||
#
|
||||
# Use this to start a certain configuration of windows, tabs, and panes
|
||||
# Open the launch configuration palette to access and open any launch configuration
|
||||
#
|
||||
# This file defines your launch configuration
|
||||
# More on how to do so here:
|
||||
# https://docs.warp.dev/features/session-management/launch-configurations
|
||||
#
|
||||
# All launch configurations are stored under ~/.warp/launch_configurations/
|
||||
# Edit them anytime!
|
||||
#
|
||||
# You can also add commands that run on-start for your launch configurations like so:
|
||||
# ---
|
||||
# name: Example with Command
|
||||
# windows:
|
||||
# - tabs:
|
||||
# - layout:
|
||||
# cwd: /Users/warp-user/project
|
||||
# commands:
|
||||
# - exec: code .
|
||||
|
||||
---
|
||||
name: Triggerdotdev
|
||||
windows:
|
||||
- tabs:
|
||||
- title: webapp
|
||||
layout:
|
||||
split_direction: vertical
|
||||
panes:
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: pnpm run dev --filter webapp
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev/apps/webapp
|
||||
- title: ngrok
|
||||
layout:
|
||||
split_direction: horizontal
|
||||
panes:
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: ./scripts/proxy-webapp.sh <your-trigger-dev>
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev
|
||||
commands:
|
||||
- exec: ./scripts/proxy-pizzly.sh <your-pizzly-dev>
|
||||
- title: wss and examples
|
||||
layout:
|
||||
split_direction: horizontal
|
||||
panes:
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev/apps/wss
|
||||
commands:
|
||||
- exec: LOG_LEVEL=debug pnpm run dev
|
||||
- cwd: /Users/eric/code/triggerdotdev/trigger.dev/examples
|
||||
- title: emails
|
||||
layout:
|
||||
split_direction: horizontal
|
||||
panes:
|
||||
- cwd: /Users/eric/Work/Git/APIHero/trigger.dev/packages/emails
|
||||
commands:
|
||||
- exec: pnpm run dev
|
||||
- cwd: /Users/eric/Work/Git/APIHero/trigger.dev/packages/emails
|
||||
@@ -4,23 +4,26 @@ Trigger.dev uses [changesets](https://github.com/changesets/changesets) to manag
|
||||
|
||||
## Adding a changeset
|
||||
|
||||
To add a changeset, use `pnpm run changeset:add` and follow the instructions [here](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md). Please only ever select one of our public packages when adding a changeset, which currently are:
|
||||
To add a changeset, use `pnpm run changeset:add` and follow the instructions [here](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md). Please only ever select one of our public packages when adding a changeset.
|
||||
|
||||
- `@trigger.dev/sdk`
|
||||
- `@trigger.dev/integration-sdk`
|
||||
- `@trigger.dev/github`
|
||||
- `@trigger.dev/slack`
|
||||
- `@trigger.dev/shopify`
|
||||
- `@trigger.dev/resend`
|
||||
|
||||
## Release instructions
|
||||
## Release instructions (local only)
|
||||
|
||||
Based on the instructions [here](https://github.com/changesets/changesets/blob/main/docs/intro-to-using-changesets.md)
|
||||
|
||||
1. Run `pnpm run changeset:version`
|
||||
2. Run `pnpm run changeset:release`
|
||||
|
||||
## Release instructions (CI)
|
||||
|
||||
Please follow the best-practice of adding changesets in the same commit as the code making the change with `pnpm run changeset:add`, as it will allow our release.yml CI workflow to function properly:
|
||||
|
||||
- Anytime new changesets are added in a commit in the `main` branch, the [release.yml](./.github/workflows/release.yml) workflow will run and will automatically create/update a PR with a fresh run of `pnpm run changeset:version`.
|
||||
- When the version PR is merged into `main`, the release.yml workflow will automatically run `pnpm run changeset:release` to build and release packages to npm.
|
||||
|
||||
## Pre-release instructions
|
||||
|
||||
- Switch into pre-release mode by running `pnpm run changeset:next`.
|
||||
- Switch back into normal mode by running `pnpm run changeset:normal`.
|
||||
1. Add changesets as usual `pnpm run changeset:add`
|
||||
2. Switch to pre-release mode by running `pnpm run changeset:next`
|
||||
3. Create version `pnpm run changeset:version`
|
||||
4. Release `pnpm run changeset:release`
|
||||
5. Switch back to normal mode by running `pnpm run changeset:normal`
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
# Contributing to Trigger.dev
|
||||
|
||||
Thank you for taking the time to contribute to Trigger.dev. Your involvement is not just welcomed, but we encourage it! 🚀
|
||||
|
||||
Please take some time to read this guide to understand contributing best practices for Trigger.dev.
|
||||
|
||||
Thank you for helping us make Trigger.dev even better! 🤩
|
||||
|
||||
## Developing
|
||||
|
||||
The development branch is `main`. This is the branch that all pull
|
||||
requests should be made against. The changes on the `main`
|
||||
branch are tagged into a release monthly.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Node.js](https://nodejs.org/en) version >=16.x
|
||||
- [pnpm package manager](https://pnpm.io/installation) version 7
|
||||
- [Docker](https://www.docker.com/get-started/)
|
||||
|
||||
### Setup
|
||||
|
||||
1. Clone the repo into a public GitHub repository or [fork the repo](https://github.com/triggerdotdev/trigger.dev/fork). If you plan to distribute the code, keep the source code public to comply with the [Apache Licence 2.0](https://github.com/triggerdotdev/trigger.dev/blob/main/LICENSE).
|
||||
|
||||
```
|
||||
git clone https://github.com/triggerdotdev/trigger.dev.git
|
||||
```
|
||||
|
||||
> If you are on windows, run the following command on gitbash with admin privileges:
|
||||
> `git clone -c core.symlinks=true https://triggerdotdev/trigger.dev.git`
|
||||
|
||||
2. Navigate to the project folder
|
||||
```
|
||||
cd trigger.dev
|
||||
```
|
||||
3. Install the required packages using pnpm.
|
||||
```
|
||||
pnpm i
|
||||
```
|
||||
4. Create your `.env` files
|
||||
```
|
||||
cp .env.example .env && cp packages/database/.env.example packages/database/.env
|
||||
```
|
||||
5. Open the root `.env` file and generate a new value for `ENCRYPTION_KEY`:
|
||||
|
||||
`ENCRYPTION_KEY` is used to two-way encrypt OAuth access tokens and so you'll probably want to actually generate a unique value, and it must be a random 16 byte hex string. You can generate one with the following command:
|
||||
|
||||
```sh
|
||||
openssl rand -hex 16
|
||||
```
|
||||
|
||||
Feel free to update `SESSION_SECRET` and `MAGIC_LINK_SECRET` as well using the same method.
|
||||
|
||||
6. Start Docker. This starts the required services like Postgres. If this is your first time using Docker, consider going through this [guide](DOCKER_INSTALLATION.md)
|
||||
```
|
||||
pnpm run docker
|
||||
```
|
||||
7. Migrate the database
|
||||
```
|
||||
pnpm run db:migrate
|
||||
```
|
||||
8. Build the app
|
||||
```
|
||||
pnpm run build --filter webapp
|
||||
```
|
||||
9. Run the seed script
|
||||
```
|
||||
pnpm run db:seed
|
||||
```
|
||||
10. Run the app. See the section below.
|
||||
|
||||
## Running
|
||||
|
||||
1. You can run the app with:
|
||||
|
||||
```
|
||||
pnpm run dev --filter webapp
|
||||
```
|
||||
|
||||
It should run on port `3030`: [http://localhost:3030](http://localhost:3030/)
|
||||
|
||||
2. Once the app is running click the magic link button and enter your email.
|
||||
3. Check your terminal, the magic link email should have printed out as following:
|
||||
|
||||
```sh
|
||||
webapp:dev: Log in to Trigger.dev
|
||||
webapp:dev:
|
||||
webapp:dev: Click here to log in with this magic link
|
||||
webapp:dev: [http://localhost:3030/magic?token=U2FsdGVkX18OvB0JxgaswTLCSbaRz%2FY82TN0EZWhSzFyZYwgG%2BIzKVTkeiaOtWfotPw7F8RwFzCHh53aBpMEu%2B%2B%2FItb%2FcJYh89MSjc3Pz92bevoEjqxSQ%2Ff%2BZbks09JOpqlBbYC3FzGWC8vuSVFBlxqLXxteSDLthZSUaC%2BS2LaA%2BJgp%2BLO7hgjAaC2lXbCHrM7MTgTdXOFt7i0Dvvuwz6%2BWY25RnfomZOPqDsyH0xz8Q2rzPTz0Xu53WSXrZ1hd]
|
||||
webapp:dev:
|
||||
webapp:dev: If you didn't try to log in, you can safely ignore this email.
|
||||
```
|
||||
|
||||
Paste the magic link shown in your terminal into your browser to login.
|
||||
|
||||
## Adding and running migrations
|
||||
|
||||
1. Modify packages/database/prisma/schema.prisma file
|
||||
2. Change directory to the packages/database folder
|
||||
```sh
|
||||
cd packages/database
|
||||
```
|
||||
3. Generate the Prisma client
|
||||
|
||||
```sh
|
||||
pnpm run generate
|
||||
```
|
||||
|
||||
The above updates the prisma client generated into node_modules/.prisma/client folder. This helps with typing of relevant prisma models. It ensures typescript
|
||||
recognizes fields added or removed from a model and type-checks appropriately.
|
||||
|
||||
4. Create and apply the migrations
|
||||
|
||||
```
|
||||
pnpm run db:migrate:dev
|
||||
```
|
||||
|
||||
This creates a migration file and executes the migrations against your database and applies changes to the database schema(s)
|
||||
|
||||
5. Commit generated migrations as well as changes to the schema.prisma file
|
||||
6. If you're using VSCode you may need to restart the Typescript server in the webapp to get updated type inference. Open a TypeScript file, then open the Command Palette (View > Command Palette) and run `TypeScript: Restart TS server`.
|
||||
|
||||
## Testing CLI changes
|
||||
|
||||
To test CLI changes, follow the steps below:
|
||||
|
||||
1. Build the CLI and watch for changes
|
||||
|
||||
```sh
|
||||
cd packages/cli
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
2. Open a new Terminal window and run the webapp locally and then create a new project in the dashboard. Copy out the dev API key.
|
||||
|
||||
3. Create a new temporary Next.js app in examples directory
|
||||
|
||||
```sh
|
||||
pnpm create next-app@latest
|
||||
```
|
||||
|
||||
Follow the prompts to create a TypeScript project using the App Directory.
|
||||
|
||||
4. Then once that's finished, add the `@trigger.dev/cli` to the `devDependencies` of the newly created Next.js app's `package.json` file, like so:
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": { "@trigger.dev/cli": "workspace:*" }
|
||||
}
|
||||
```
|
||||
|
||||
5. Open a new terminal window, navigate into the example, and initialize the CLI:
|
||||
|
||||
```sh
|
||||
cd examples/your-newly-created-nextjs-project
|
||||
pnpm i
|
||||
pnpm exec trigger-cli init
|
||||
```
|
||||
|
||||
6. When prompted, select `self-hosted` and enter `localhost:3030` for your local version of the webapp. When asked for an API key, use the key you copied earlier.
|
||||
|
||||
7. Run the CLI
|
||||
|
||||
```sh
|
||||
pnpm exec trigger-cli dev
|
||||
```
|
||||
|
||||
8. After running the CLI, start your newly created Next.js project. You should now be able to see the changes.
|
||||
|
||||
9. Please remember to delete the temporary project you created after you've tested the changes, and before you raise a PR.
|
||||
|
||||
## Add sample jobs
|
||||
|
||||
The [examples/jobs-starter](./examples/jobs-starter/) project defines simple jobs you can get started with.
|
||||
|
||||
1. `cd` into `examples/jobs-starter`
|
||||
2. Create a `.env.local` file with the following content,
|
||||
replacing `[TRIGGER_DEV_API_KEY]` with an actual key:
|
||||
|
||||
```env
|
||||
TRIGGER_API_KEY=[TRIGGER_DEV_API_KEY]
|
||||
TRIGGER_API_URL=http://localhost:3030
|
||||
```
|
||||
|
||||
`TRIGGER_API_URL` is used to configure the URL for your Trigger.dev instance,
|
||||
where the jobs will be registered.
|
||||
|
||||
3. Run the `jobs-starter` app:
|
||||
|
||||
```sh
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
4. Navigate to your trigger.dev instance ([http://localhost:3030](http://localhost:3030/)), to see the jobs.
|
||||
You can use the test feature to trigger them.
|
||||
|
||||
## Making a pull request
|
||||
|
||||
**If you get errors, be sure to fix them before committing.**
|
||||
|
||||
- Be sure to [check the "Allow edits from maintainers" option](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) while creating you PR.
|
||||
- If your PR refers to or fixes an issue, be sure to add `refs #XXX` or `fixes #XXX` to the PR description. Replacing `XXX` with the respective issue number. See more about [Linking a pull request to an issue
|
||||
](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
|
||||
- Be sure to fill the PR Template accordingly.
|
||||
|
||||
## Adding changesets
|
||||
|
||||
We use [changesets](https://github.com/changesets/changesets) to manage our package versions and changelogs. If you've never used changesets before, first read [their guide here](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).
|
||||
|
||||
If you are contributing a change to any packages in this monorepo (anything in either the `/packages` or `/integrations` directories), then you will need to add a changeset to your Pull Requests before they can be merged.
|
||||
|
||||
To add a changeset, run the following command in the root of the repo
|
||||
|
||||
```sh
|
||||
pnpm run changeset:add
|
||||
```
|
||||
|
||||
Here's an example of creating a `patch` changeset for the `@trigger.dev/github` and `@trigger.dev/slack` packages (click to view):
|
||||
|
||||
[](https://asciinema.org/a/599228)
|
||||
|
||||
You will be prompted to select which packages to include in the changeset. Only select the packages that you have made changes for.
|
||||
|
||||
Most of the time the changes you'll make are likely to be categorized as patch releases. If you feel like there is the need for a minor or major release of the package based on the changes being made, add the changeset as such and it will be discussed during PR review.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### EADDRINUSE: address already in use :::3030
|
||||
|
||||
When receiving the following error message:
|
||||
|
||||
```sh
|
||||
webapp:dev: Error: listen EADDRINUSE: address already in use :::3030
|
||||
```
|
||||
|
||||
The process running on port `3030` should be destroyed.
|
||||
|
||||
1. Get the `PID` of the process running on PORT `3030`
|
||||
```sh
|
||||
lsof -i :3030
|
||||
```
|
||||
2. Kill the process
|
||||
```sh
|
||||
sudo kill -9 <PID>
|
||||
```
|
||||
@@ -1,32 +0,0 @@
|
||||
# Trigger.dev Deployment Guide
|
||||
|
||||
## StreamNative Cloud - Hosted Pulsar
|
||||
|
||||
### Generic client credentials
|
||||
|
||||
```sh
|
||||
snctl auth export-service-account webapp --key-file webapp-credentials.json
|
||||
snctl auth export-service-account websocketserver --key-file wss-credentials.json
|
||||
```
|
||||
|
||||
### Topics
|
||||
|
||||
#### Triggers (`persistent://triggerdotdev/workflows/triggers`)
|
||||
|
||||
Events that trigger workflows to run. These are sent by the "platform" and read by the Web Socket Servers, which then coordinate with the hosts for running the workflows
|
||||
|
||||
#### Run Commands (`persistent://triggerdotdev/workflows/run-commands`)
|
||||
|
||||
These are events that come from hosts and are published by the Web Socket Servers, e.g. Sending Integration Requests, Sending Logs, Initializing a Delay
|
||||
|
||||
#### Run Command Responses (`persistent://triggerdotdev/workflows/run-command-responses`)
|
||||
|
||||
These are events that come from the platform and are read by the Web Socket Servers, to resolve or reject a previous Run Command
|
||||
|
||||
#### Integration Requests (`persistent://triggerdotdev/queues/integration-requests`)
|
||||
|
||||
This is an internal queue used by the platform to perform integration requests, and retry them.
|
||||
|
||||
#### App Task Queue (`persistent://triggerdotdev/queues/background-tasks`)
|
||||
|
||||
This is an internal queue used by the platform to do tasks in a queue. Basically a background job system.
|
||||
@@ -1,229 +0,0 @@
|
||||
# Initial setup
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Pulsar requirements
|
||||
|
||||
1. Ensure you have Homebrew installed by running `which brew` in terminal. If it's not found then you should install it: https://brew.sh/. Run `which brew` again to check it's found. If it's not you may need to [add it your path](https://stackoverflow.com/questions/36657321/after-installing-homebrew-i-get-zsh-command-not-found-brew)
|
||||
|
||||
2. Run `brew install libpulsar` to install the C++ libraries that the pulsar-client depends on
|
||||
|
||||
3. Make sure you have Python installed on your machine by running `which python3` in terminal.
|
||||
|
||||
4. If python isn't found then you should install it: https://www.python.org/downloads/. In a new terminal window run `which python3` again.
|
||||
|
||||
5. Run `npm config set python /the/path/from/the/which/python3/command` inserting the path from step 2 or 3
|
||||
|
||||
6. Install node-gyp: `npm install -g node-gyp`
|
||||
|
||||
7. Make sure you have the Xcode command line tools installed by running `xcode-select --install` from the terminal. If it says they're already installed then you're set.
|
||||
|
||||
8. Run this in the terminal:
|
||||
|
||||
```sh
|
||||
export CPLUS_INCLUDE_PATH="$CPLUS_INCLUDE_PATH:$(brew --prefix)/include"
|
||||
export LIBRARY_PATH="$LIBRARY_PATH:$(brew --prefix)/lib"
|
||||
export PULSAR_CPP_DIR=/opt/homebrew/Cellar/libpulsar/3.1.0
|
||||
```
|
||||
|
||||
9. Run `pnpm install` in the same terminal window.
|
||||
|
||||
## Building and running the webapp
|
||||
|
||||
> **Warning**
|
||||
> All the following commands should be launched from the **monorepo root directory**
|
||||
|
||||
1. Install the dependencies.
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
2. Optionally, if you are testing auth (pizzly) or webhooks (webapp) then you'll need to use ngrok to proxy internet traffic to your local machine
|
||||
|
||||
Get access to ngrok and then follow the instructions here to get it setup: https://ngrok.com/download (use homebrew) and make sure to authenticate.
|
||||
|
||||
Then run the following scripts to start proxying:
|
||||
|
||||
```sh
|
||||
./scripts/proxy-pizzly.sh dan-pizzly-dev
|
||||
./scripts/proxy-webapp.sh dan-trigger-dev
|
||||
```
|
||||
|
||||
3. Environment variables. You will need to create copies of the `.env.example` files in `app/webapp`
|
||||
|
||||
```sh
|
||||
cp ./apps/webapp/.env.example ./apps/webapp/.env
|
||||
```
|
||||
|
||||
Then you will need to fill in the fields with real values.
|
||||
|
||||
You also need to create the `pizzly-server.env` files under the `.docker` directory:
|
||||
|
||||
```sh
|
||||
cp ./.docker/pizzly-server.env.example ./.docker/pizzly-server.env
|
||||
```
|
||||
|
||||
Next, update the `AUTH_CALLBACK_URL` env var in the `pizzly-server.env` env file with the value provided to the `./scripts/proxy-pizzly.sh` command. Using the example above the `AUTH_CALLBACK_URL` would be `AUTH_CALLBACK_URL=https://dan-pizzly-dev.eu.ngrok.io/oauth/callback`.
|
||||
|
||||
If you aren't proxying pizzly according to step 2, then leave the `pizzly-server.env` file empty.
|
||||
|
||||
If you are proxying the webapp according to step 2 then in `webapp/.env`, set the `APP_ORIGIN` to the `NGROK_SUBDOMAIN` provided to the `./scripts/proxy-webapp.sh` command, e.g. `APP_ORIGIN=https://dan-trigger-dev.eu.ngrok.io`
|
||||
|
||||
4. Start postgresql, pulsar, and pizzly server
|
||||
|
||||
```bash
|
||||
pnpm run docker:db
|
||||
```
|
||||
|
||||
> **Note:** The npm script will complete while Docker sets up the container in the background. Ensure that Docker has finished and your container is running before proceeding.
|
||||
|
||||
5. Generate prisma schema
|
||||
```bash
|
||||
pnpm run generate
|
||||
```
|
||||
6. Run the Prisma migration to the database
|
||||
|
||||
```bash
|
||||
pnpm run db:migrate:deploy
|
||||
```
|
||||
|
||||
7. Run the first build (with dependencies via the `...` option)
|
||||
|
||||
```bash
|
||||
pnpm run build --filter=webapp...
|
||||
```
|
||||
|
||||
**Running simply `pnpm run build` will build everything, including the Remix app.**
|
||||
|
||||
8. Run the Remix dev server
|
||||
|
||||
```bash
|
||||
pnpm run dev --filter=webapp
|
||||
```
|
||||
|
||||
## Attaching an API integration using Pizzly
|
||||
|
||||
```bash
|
||||
PIZZLY_HOSTPORT=http://localhost:3004 npx pizzly config:create github github <client-id> <client-secret> "repo,user"
|
||||
```
|
||||
|
||||
## Tests, Typechecks, Lint, Install packages...
|
||||
|
||||
Check the `turbo.json` file to see the available pipelines.
|
||||
|
||||
- Run the Cypress tests and Dev
|
||||
```bash
|
||||
pnpm run test:e2e:dev --filter=webapp
|
||||
```
|
||||
- Lint everything
|
||||
```bash
|
||||
pnpm run lint
|
||||
```
|
||||
- Typecheck the whole monorepo
|
||||
```bash
|
||||
pnpm run typecheck
|
||||
```
|
||||
- Test the whole monorepo
|
||||
```bash
|
||||
pnpm run test
|
||||
or
|
||||
pnpm run test:dev
|
||||
```
|
||||
- How to install an npm package in the Remix app ?
|
||||
```bash
|
||||
pnpm add dayjs --filter webapp
|
||||
```
|
||||
- Tweak the tsconfigs, eslint configs in the `config-package` folder. Any package or app will then extend from these configs.
|
||||
|
||||
# Running a workflow locally
|
||||
|
||||
## After pulling a change
|
||||
|
||||
1. Ensure there are no database migrations to run
|
||||
|
||||
```bash
|
||||
pnpm run db:migrate:dev
|
||||
```
|
||||
|
||||
2. Generate the Prisma database client
|
||||
|
||||
```bash
|
||||
pnpm run generate
|
||||
```
|
||||
|
||||
3. Install packages
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
4. Build everything
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
5. Install packages again, this makes sure the local packages are linked
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## Running the servers
|
||||
|
||||
1. Ensure the docker containers are running
|
||||
|
||||
```bash
|
||||
pnpm run docker:db
|
||||
```
|
||||
|
||||
2. Run the webapp
|
||||
|
||||
```bash
|
||||
pnpm run dev --filter=webapp
|
||||
```
|
||||
|
||||
3. Run the Web Socket Server
|
||||
|
||||
```bash
|
||||
pnpm run dev --filter=wss
|
||||
```
|
||||
|
||||
4. Build all the @trigger.dev/\* packages
|
||||
|
||||
```bash
|
||||
pnpm run dev --filter="@trigger.dev/*"
|
||||
```
|
||||
|
||||
## Running the smoke test
|
||||
|
||||
1. Run the smoke test workflow
|
||||
|
||||
```bash
|
||||
cd ./examples/smoke-test
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
2. Running the workflow requires you to send data to the local API.
|
||||
|
||||
You can use this cURL command to send a `user.created` event. This will run the workflow and generate the corresponding logs.
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url http://localhost:3000/api/v1/events \
|
||||
--header 'Authorization: Bearer trigger_dev_zC25mKNn6c0q' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"name": "user.created",
|
||||
"payload": {
|
||||
"id": "123"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
## Dependency & Package graph
|
||||
|
||||

|
||||
|
||||
## Warp Launch Configuration
|
||||
|
||||
Setup a custom launch configuration for the Warp terminal ([docs here](https://docs.warp.dev/features/sessions/launch-configurations)) by copying the `.warp/triggerdotdev.yaml.example` file to `~/.warp/launch_configurations/triggerdotdev.yaml`. Make sure you edit the file and replace `<your-trigger-dev>` and `<your-pizzly-dev>` with your custom ngrok subdomains.
|
||||
@@ -0,0 +1,126 @@
|
||||
This guide covers installing Docker and Docker Compose. If you're looking for instructions for running Trigger.dev in docker, [see here](https://github.com/triggerdotdev/docker).
|
||||
|
||||
## Setting up Docker for the first time.
|
||||
|
||||
In the contributing guide of Trigger.dev, there's a section that requires you to start Docker.
|
||||
|
||||
If you don't have Docker installed on your machine, you'll run into some complications (errors).
|
||||
|
||||
Below are the steps on how you can avoid that.
|
||||
|
||||
First you need to setup docker-compose as it is an underlying tool that this command: `pnpm run docker` fires behind the scene.
|
||||
|
||||
## Linux
|
||||
|
||||
To install Docker Compose on Linux Ubuntu via the terminal, you can follow these steps:
|
||||
|
||||
1. Update the package index on your system by running the following command:
|
||||
|
||||
```shell
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
2. Install the required dependencies by running the following command:
|
||||
|
||||
```shell
|
||||
sudo apt install curl
|
||||
```
|
||||
|
||||
3. Download the Docker Compose binary into the `/usr/local/bin` directory using the `curl` command:
|
||||
|
||||
```shell
|
||||
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
```
|
||||
|
||||
4. Set the appropriate permissions to make the `docker-compose` binary executable:
|
||||
|
||||
```shell
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
```
|
||||
|
||||
5. Verify that Docker Compose has been successfully installed by running the following command:
|
||||
|
||||
```shell
|
||||
docker-compose --version
|
||||
```
|
||||
|
||||
This command should display the version information of Docker Compose without any errors.
|
||||
|
||||
After following these steps, you should have Docker Compose installed on your Ubuntu system, and you can use it by running `docker-compose` commands in the terminal.
|
||||
|
||||
When you've verified that the `docker-compose` package is installed and you proceed to start Docker with `pnpm run docker`.
|
||||
|
||||
You'll probably get an error similar to the one below:
|
||||
|
||||
```shell
|
||||
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
|
||||
ELIFECYCLE Command failed with exit code 1.
|
||||
```
|
||||
|
||||
The error message suggests that the Docker daemon is not running on your system. The Docker daemon is responsible for managing and running Docker containers.
|
||||
|
||||
To resolve this issue, you may need to install Docker properly on your Ubuntu system. Here are the steps to install Docker on Ubuntu:
|
||||
|
||||
1. Update the package index on your system by running the following command:
|
||||
|
||||
```shell
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
2. Install the necessary packages to allow apt to use repositories over HTTPS:
|
||||
|
||||
```shell
|
||||
sudo apt install apt-transport-https ca-certificates curl software-properties-common
|
||||
```
|
||||
|
||||
3. Add the official Docker GPG key to your system by running the following command:
|
||||
|
||||
```shell
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
```
|
||||
|
||||
4. Add the Docker repository to the APT sources list:
|
||||
|
||||
```shell
|
||||
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
```
|
||||
|
||||
5. Update the package index again:
|
||||
|
||||
```shell
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
6. Install Docker by running the following command:
|
||||
|
||||
```shell
|
||||
sudo apt install docker-ce docker-ce-cli containerd.io
|
||||
```
|
||||
|
||||
7. After the installation is complete, verify that Docker is installed correctly by running the following command:
|
||||
|
||||
```shell
|
||||
docker --version
|
||||
```
|
||||
|
||||
This command should display the version information of Docker without any errors.
|
||||
|
||||
Once Docker is installed and verified, you should be able to start the Docker daemon and run the `pnpm run docker` command without encountering any issues.
|
||||
|
||||
## Windows
|
||||
|
||||
1. Download the Docker Desktop installer from the Docker website: [Docker Desktop for Windows](https://www.docker.com/products/docker-desktop)
|
||||
|
||||
2. Run the installer and follow the instructions to install Docker Desktop.
|
||||
|
||||
3. After installation, Docker Desktop should be running automatically.
|
||||
|
||||
## macOS
|
||||
|
||||
1. Download the Docker Desktop installer from the Docker website: [Docker Desktop for Mac](https://www.docker.com/products/docker-desktop)
|
||||
|
||||
2. Run the installer and follow the instructions to install Docker Desktop.
|
||||
|
||||
3. After installation, Docker Desktop should be running automatically.
|
||||
|
||||
Please note that the instructions provided above are for the most common scenarios. For specific versions or different distributions, it's always a good idea to consult the official Docker documentation for the respective operating systems.
|
||||
@@ -1,25 +1,201 @@
|
||||
Copyright (c) 2022 API Hero Inc.
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
- All content that resides under any "ee/" directory of this repository, if such directories exists, are licensed under the license defined in "ee/LICENSE".
|
||||
- All third party components incorporated into the Trigger.dev Software are licensed under the original license provided by the owner of the applicable component.
|
||||
- Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
|
||||
1. Definitions.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -1,204 +1,65 @@
|
||||
<div align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://imagedelivery.net/3TbraffuDZ4aEf8KWOmI_w/a45d1fa2-0ae8-4a39-4409-f4f934bfae00/public">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://imagedelivery.net/3TbraffuDZ4aEf8KWOmI_w/3f5ad4c1-c4c8-4277-b622-290e7f37bd00/public">
|
||||
<img alt="Trigger.dev logo" src="https://imagedelivery.net/3TbraffuDZ4aEf8KWOmI_w/a45d1fa2-0ae8-4a39-4409-f4f934bfae00/public">
|
||||
</picture>
|
||||
|
||||
### The background jobs framework for Next.js
|
||||
|
||||

|
||||
[Discord](https://discord.gg/JtBAxBr2m3) | [Website](https://trigger.dev) | [Issues](https://github.com/triggerdotdev/trigger.dev/issues) | [Docs](https://trigger.dev/docs)
|
||||
|
||||
[](https://twitter.com/triggerdotdev) [](https://www.youtube.com/@triggerdotdev)
|
||||
[](https://twitter.com/triggerdotdev)
|
||||
[](https://github.com/triggerdotdev/trigger.dev)
|
||||
|
||||
[Website](https://trigger.dev) | [Community](https://discord.gg/JtBAxBr2m3) | [Docs](https://docs.trigger.dev)
|
||||
</div>
|
||||
|
||||
# About Trigger.dev
|
||||
|
||||
# **⚡️ Trigger.dev**
|
||||
### **The developer-first open source Zapier alternative.**
|
||||
Create long-running jobs directly in your codebase with features like API integrations, webhooks, scheduling and delays.
|
||||
|
||||
### Long running Jobs on serverless
|
||||
|
||||
Trigger.dev is an open source platform that makes it easy for developers to create event-driven background tasks directly in their code. Build, test and run workflows locally using our SDK. Subscribe to webhooks, schedule jobs, run background jobs and add long delays easily and reliably. In our web app you get full visibility of every run your workflow has ever made making it easier to monitor and debug.
|
||||
Reliably run jobs and don’t worry about function timeouts, we handle those for you.
|
||||
|
||||
|
||||
- Auto-resume after a function timeout
|
||||
- Auto-resume after a server outage
|
||||
- Add delays of up to a year
|
||||
|
||||
# **⭐️ Features:**
|
||||
### In your codebase
|
||||
|
||||
- 👂 Easily subscribe to [webhooks](https://docs.trigger.dev/triggers/webhooks)
|
||||
— they work locally without tunnelling.
|
||||
- 🔥 Fire your own [custom events](https://docs.trigger.dev/triggers/custom-events)—a single event can trigger multiple workflows.
|
||||
- 📆 [Schedule workflows](https://docs.trigger.dev/triggers/scheduled)—easily repeat tasks or use CRON syntax for advanced cases.
|
||||
- 🚦 Add [long delays](https://docs.trigger.dev/functions/delays) inside workflows (up to a year) and they will pick up where they left off.
|
||||
- 🤝 When your server goes down [it’s not a problem](https://docs.trigger.dev/guides/resumability), workflows will reconnect and continue.
|
||||
- 🪧 [View every step of every run](https://docs.trigger.dev/viewing-runs), with data, previews and errors.
|
||||
- 👋 Connect to and authenticate with APIs using our custom integrations.
|
||||
- 🚗 If you have a custom use case, we support [Fetch for calling any HTTP endpoint](https://docs.trigger.dev/functions/fetch) or [webhooks](https://docs.trigger.dev/triggers/webhooks) for subscribing to events from APIs.
|
||||
- 📡 All API calls are automatically retried with exponential back off.
|
||||
- 😀 TypeScript SDK, so whether you’re using JavaScript or TypeScript you will have a great experience.
|
||||
Create Jobs where they belong: in your codebase. Version control, localhost, test, review, and deploy like you're already used to.
|
||||
|
||||
|
||||
### Secure by design
|
||||
|
||||
# **🌱 Documentation:**
|
||||
We only receive Triggers and the data you choose to send to us. You can even completely self-host the entire platform.
|
||||
|
||||
- [Getting Started with Trigger.dev](https://docs.trigger.dev/getting-started)
|
||||
- Example workflows
|
||||
- [Welcome email drip campaign using Resend and Slack](https://docs.trigger.dev/examples/resend)
|
||||
- [Post to Slack when a GitHub issue is created or modified](https://docs.trigger.dev/examples/slack)
|
||||
- [Create a new product on Shopify](https://docs.trigger.dev/examples/shopify)
|
||||
- [When a GitHub repo is starred, post information about the user to Slack](https://docs.trigger.dev/examples/github)
|
||||
- Triggers:
|
||||
- [Webhooks](https://docs.trigger.dev/triggers/webhooks)
|
||||
- [Custom events](https://docs.trigger.dev/triggers/custom-events)
|
||||
- [Scheduled](https://docs.trigger.dev/triggers/scheduled)
|
||||
- Functions:
|
||||
- [Fetch](https://docs.trigger.dev/functions/fetch)
|
||||
- [Logging](https://docs.trigger.dev/functions/logging)
|
||||
- [Delays](https://docs.trigger.dev/functions/delays)
|
||||
- [Send event](https://docs.trigger.dev/functions/send-event)
|
||||
- [Loops, conditionals, etc](https://docs.trigger.dev/functions/loops-conditionals-etc)
|
||||
### Don't worry about deployment
|
||||
|
||||
|
||||
Just use our SDK to write Jobs in your Next.js codebase. There's nothing extra to deploy and no CI to configure, your Jobs just connect to our cloud. Or you can always self-host.
|
||||
|
||||
# 🔬 **Anatomy of a workflow**
|
||||
### Full visibility of every job run
|
||||
|
||||
* You create workflows in code on your server using our SDK
|
||||
* Each API integration is a separate package, e.g. `@trigger.dev/slack`
|
||||
* Each workflow has an event that triggers it, e.g. `github.events.newStarEvent`, `scheduleEvent`, `customEvent`
|
||||
* Each workflow has a `run` function that is called when the event is triggered
|
||||
* If we don't have an integration for the API you want to use, you can use `fetch` to call any HTTP endpoint and `webhookEvent` to subscribe to webhooks
|
||||
View every Task in every Run so you can tell exactly what happened.
|
||||
|
||||
## **Example workflows**
|
||||

|
||||
|
||||
<details open><summary> Post to Slack when a GitHub issue is created or modified
|
||||
</summary>
|
||||
### Built-in integrations
|
||||
|
||||
_Integrations required: Slack, GitHub_
|
||||
Easily integrate with hundreds of third-party APIs – including your own. Use API keys (which never leave your server) or let us handle OAuth for you. Install our integration packages and easily subscribe to webhooks and perform common tasks, or you can easily use your existing favorite Node.JS SDKs and get resumability and idempotency through our `runTask` function.
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
### Trigger.dev Connect (coming soon)
|
||||
|
||||
new Trigger({
|
||||
id: "new-github-star-to-slack",
|
||||
name: "New GitHub Star: triggerdotdev/trigger.dev",
|
||||
apiKey: "<my_api_key>",
|
||||
on: github.events.newStarEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event) => {
|
||||
await slack.postMessage("github-stars", {
|
||||
channelName: "github-stars",
|
||||
text: `New GitHub star from \n<${event.sender.html_url}|${event.sender.login}>`,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
Easily add integrations for your users.
|
||||
|
||||
</details>
|
||||
# Getting started
|
||||
|
||||
<details><summary>Welcome email drip campaign
|
||||
</summary>
|
||||
Visit our docs [here](https://trigger.dev/docs).
|
||||
|
||||
_Integrations required: Slack, Resend_
|
||||
## Self-host
|
||||
|
||||
```ts
|
||||
import { customEvent, Trigger, sendEvent } from "@trigger.dev/sdk";
|
||||
import * as resend from "@trigger.dev/resend";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import React from "react";
|
||||
import { z } from "zod";
|
||||
import { getUser } from "../db";
|
||||
import { InactiveEmail, TipsEmail, WelcomeEmail } from "./email-templates";
|
||||
We provide an official trigger.dev docker image you can use to easily self-host the platform. We're working on more extensive guides but we currently provide a [Fly.io example repository](https://github.com/triggerdotdev/fly.io) with instructions in the README for deploying and using a self-hosted instance of Trigger.dev on Fly.io.
|
||||
|
||||
new Trigger({
|
||||
id: "welcome-email-campaign",
|
||||
name: "Welcome email drip campaign",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({
|
||||
userId: z.string(),
|
||||
}),
|
||||
}),
|
||||
async run(event, context) {
|
||||
//get the user data from the database
|
||||
const user = await getUser(event.userId);
|
||||
## Development
|
||||
|
||||
await slack.postMessage("send-to-slack", {
|
||||
channelName: "new-users",
|
||||
text: `New user signed up: ${user.name} (${user.email})`,
|
||||
});
|
||||
|
||||
//Send the first email
|
||||
const welcomeResponse = await resend.sendEmail("welcome-email", {
|
||||
from: "Trigger.dev <james@email.trigger.dev>",
|
||||
replyTo: "James <james@trigger.dev>",
|
||||
to: user.email,
|
||||
subject: "Welcome to Trigger.dev",
|
||||
react: <WelcomeEmail name={user.name} />,
|
||||
});
|
||||
await context.logger.debug(
|
||||
`Sent welcome email to ${welcomeResponse.to} with id ${welcomeResponse.id}`
|
||||
);
|
||||
|
||||
//wait 1 day, check if the user has created a workflow and send the appropriate email
|
||||
await context.waitFor("wait-a-while", { days: 1 });
|
||||
const updatedUser = await getUser(event.userId);
|
||||
|
||||
if (updatedUser.hasOnboarded) {
|
||||
await resend.sendEmail("onboarding-complete", {
|
||||
from: "Trigger.dev <james@email.trigger.dev>",
|
||||
replyTo: "James <james@trigger.dev>",
|
||||
to: updatedUser.email,
|
||||
subject: "Pro tips for workflows",
|
||||
react: <TipsEmail name={updatedUser.name} />,
|
||||
});
|
||||
} else {
|
||||
await resend.sendEmail("onboarding-incomplete", {
|
||||
from: "Trigger.dev <james@email.trigger.dev>",
|
||||
replyTo: "James <james@trigger.dev>",
|
||||
to: updatedUser.email,
|
||||
subject: "Help with your first workflow",
|
||||
react: <InactiveEmail name={updatedUser.name} />,
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
[More examples here](https://docs.trigger.dev/examples/examples)
|
||||
|
||||
|
||||
|
||||
# 👀 **Viewing runs:**
|
||||
|
||||
One of the most powerful features of Trigger.dev is the [runs page](https://docs.trigger.dev/viewing-runs). All of the steps in a workflow, including the initial event, can be viewed in detail. See the status / output of each step, the logs, rich previews, errors and much more.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
# **🏠 Running Trigger.dev locally:**
|
||||
|
||||
To run Trigger.dev locally, [follow these steps](https://github.com/triggerdotdev/trigger.dev/blob/main/DEVELOPMENT.md).
|
||||
|
||||
|
||||
|
||||
# **👏 Contributing:**
|
||||
|
||||
We are open source and love contributions!
|
||||
|
||||
- Request a feature in our [Discord community](https://discord.gg/JtBAxBr2m3)
|
||||
- Open a PR
|
||||
|
||||
|
||||
|
||||
# **🧘♂️ Self-hosting guide:**
|
||||
|
||||
_coming soon..._
|
||||
|
||||
|
||||
|
||||
# **📧 Support & contact:**
|
||||
|
||||
- Join our [Discord community](https://discord.gg/JtBAxBr2m3)
|
||||
- If you have any other questions, get in touch at [hello@trigger.dev](mailto:hello@trigger.dev)
|
||||
To setup and develop locally or contribute to the open source project, follow our [developement guide](./CONTRIBUTING.md).
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
# Mintlify Starter Kit
|
||||
|
||||
Click on `Use this template` to quickstarter your documentation setup with Mintlify. The starter kit contains examples including
|
||||
|
||||
- Guide pages
|
||||
- Navigation
|
||||
- Customizations
|
||||
- API Reference pages
|
||||
- Use of popular components
|
||||
|
||||
### 👩💻 Development
|
||||
|
||||
Run these from the root of the repository
|
||||
|
||||
```
|
||||
pnpm install --filter docs
|
||||
```
|
||||
|
||||
```
|
||||
pnpm run dev --filter docs
|
||||
```
|
||||
|
||||
Go to http://localhost:3050
|
||||
|
||||
### 😎 Publishing Changes
|
||||
|
||||
Changes will be deployed to production automatically after pushing to the default branch.
|
||||
|
||||
You can also preview changes using PRs, which generates a preview link of the docs.
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
- Mintlify dev isn't running - Run `mintlify install` it'll re-install dependencies.
|
||||
- Mintlify dev is updating really slowly - Run `mintlify clear` to clear the cache.
|
||||
@@ -1,204 +0,0 @@
|
||||
The following example combines WhatsApp and Slack to create a workflow that allows you to receive WhatsApp messages in Slack, and use a modal to compose a reply.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```tsx whatsappToSlack.tsx
|
||||
/** @jsxImportSource jsx-slack */
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import {
|
||||
events,
|
||||
sendText,
|
||||
getMediaUrl,
|
||||
MessageEventMessage,
|
||||
} from "@trigger.dev/whatsapp";
|
||||
import JSXSlack, {
|
||||
Actions,
|
||||
Blocks,
|
||||
Button,
|
||||
Section,
|
||||
Header,
|
||||
Context,
|
||||
Image,
|
||||
Modal,
|
||||
Input,
|
||||
Textarea,
|
||||
} from "jsx-slack";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat("en-US", {
|
||||
timeStyle: "short",
|
||||
dateStyle: "short",
|
||||
});
|
||||
|
||||
// this trigger listens for WhatsApp messages and sends them to Slack
|
||||
new Trigger({
|
||||
id: "whatsapp-to-slack",
|
||||
name: "WhatsApp: load messages",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//this generates Slack blocks from the WhatsApp message
|
||||
const messageBody = await createMessageBody(event.message);
|
||||
|
||||
await slack.postMessage("jsx-test", {
|
||||
channelName: "whatsapp-support",
|
||||
//text appears in Slack notifications on mobile/desktop
|
||||
text: "How is your progress today?",
|
||||
//import and use JSXSlack to make creating rich messages much easier
|
||||
blocks: JSXSlack(
|
||||
<Blocks>
|
||||
<Header>From: {event.message.from}</Header>
|
||||
<Context>At: {dateFormatter.format(event.message.timestamp)}</Context>
|
||||
{messageBody}
|
||||
<Actions blockId="launch-modal">
|
||||
<Button value="reply" actionId="reply">
|
||||
Reply
|
||||
</Button>
|
||||
</Actions>
|
||||
</Blocks>
|
||||
),
|
||||
//pass the WhatsApp message to the next trigger
|
||||
metadata: {
|
||||
whatsAppMessage: event.message,
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```tsx replyButtonInteraction.tsx
|
||||
//this trigger creates a Slack modal when a user presses the Reply button
|
||||
new Trigger({
|
||||
id: "whatsapp-to-slack-modal",
|
||||
name: "WhatsApp: show message composer",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "launch-modal",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (!event.trigger_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
//get the action (pressing the reply button) and the original WhatsApp message
|
||||
const action = event.actions[0];
|
||||
const whatsAppMessage =
|
||||
event.message?.metadata?.event_payload.whatsAppMessage;
|
||||
|
||||
//generate Slack blocks from the WhatsApp message
|
||||
const messageBody = await createMessageBody(whatsAppMessage);
|
||||
|
||||
if (action.action_id === "reply" && action.type === "button") {
|
||||
//show a reply modal, with the original message and an input field for the reply
|
||||
await slack.openView(
|
||||
"Opening view",
|
||||
event.trigger_id,
|
||||
JSXSlack(
|
||||
<Modal title="Your reply" close="Cancel" callbackId="submit-message">
|
||||
<Header>Original message</Header>
|
||||
{messageBody}
|
||||
<Header>Your reply</Header>
|
||||
<Textarea
|
||||
name="message"
|
||||
label="Message"
|
||||
placeholder="Your message"
|
||||
maxLength={500}
|
||||
id="messageField"
|
||||
/>
|
||||
<Input type="submit" value="submit" />
|
||||
</Modal>
|
||||
),
|
||||
{
|
||||
onSubmit: "close",
|
||||
//pass the original WhatsApp message to the next trigger, and the original Slack message so we can thread replies
|
||||
metadata: {
|
||||
whatsAppMessage,
|
||||
thread_ts: event.message?.ts,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```tsx replyModalSubmission.tsx
|
||||
//this trigger sends the reply from Slack to WhatsApp
|
||||
new Trigger({
|
||||
id: "whatsapp-composed-slack-message",
|
||||
name: "WhatsApp: send message from Slack",
|
||||
on: slack.events.viewSubmissionInteraction({
|
||||
callbackId: "submit-message",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("Modal submission", { event });
|
||||
|
||||
//the message from the input field in Slack
|
||||
const usersResponse = event.view.state?.values.messageField.message
|
||||
.value as string;
|
||||
|
||||
//get the data from the previous messages/panels
|
||||
const privateMetadata =
|
||||
event.view.private_metadata && JSON.parse(event.view.private_metadata);
|
||||
await ctx.logger.info("Private metadata", privateMetadata);
|
||||
const whatsAppMessage = privateMetadata?.whatsAppMessage;
|
||||
|
||||
if (!whatsAppMessage || !usersResponse) {
|
||||
await ctx.logger.error("No message or original message", { event });
|
||||
return;
|
||||
}
|
||||
|
||||
//send WhatsApp message
|
||||
await sendText("send-whatsapp", {
|
||||
fromId: "102119172798864",
|
||||
to: whatsAppMessage.from,
|
||||
text: usersResponse,
|
||||
});
|
||||
|
||||
//send message in the Slack thread
|
||||
await slack.postMessage("slack-reply", {
|
||||
channelName: "whatsapp-support",
|
||||
text: `Replied with: ${usersResponse}`,
|
||||
blocks: JSXSlack(
|
||||
<Blocks>
|
||||
<Header>Reply from @{event.user.username}</Header>
|
||||
<Context>
|
||||
At: {dateFormatter.format(new Date())} To: {whatsAppMessage.from}
|
||||
</Context>
|
||||
<Section>{usersResponse}</Section>
|
||||
</Blocks>
|
||||
),
|
||||
thread_ts: privateMetadata?.thread_ts,
|
||||
});
|
||||
|
||||
return event;
|
||||
},
|
||||
}).listen();
|
||||
|
||||
//creates different Slack blocks depending on the type of WhatsApp message (e.g. text, image, etc.)
|
||||
async function createMessageBody(message: MessageEventMessage) {
|
||||
switch (message.type) {
|
||||
case "text": {
|
||||
return <Section>{message.text.body}</Section>;
|
||||
}
|
||||
case "image": {
|
||||
const mediaUrl = await getMediaUrl(`getImageUrl`, message.image);
|
||||
return (
|
||||
<Image
|
||||
src={mediaUrl}
|
||||
alt={message.image.caption ?? ""}
|
||||
title={message.image.caption ?? ""}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "video": {
|
||||
const mediaUrl = await getMediaUrl(`getVideoUrl`, message.video);
|
||||
return <Section>{mediaUrl}</Section>;
|
||||
}
|
||||
default:
|
||||
return <Section>Unsupported message type: {message.type}</Section>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
title: "Send Event"
|
||||
openapi: "POST /events"
|
||||
sidebarTitle: "Send Event"
|
||||
description: "Send a custom event to Trigger through the API."
|
||||
---
|
||||
@@ -1,28 +0,0 @@
|
||||
---
|
||||
title: "Changelog"
|
||||
description: "We release features and fixes weekly! See some of the changes we have made."
|
||||
---
|
||||
|
||||
## Feb 6 2023 Release
|
||||
|
||||
#### app.trigger.dev
|
||||
|
||||
- Improved the onboarding experience for new users, as well as users creating a new workflow.
|
||||
- Test editor now suggests example JSON for `customEvent` and `webhookEvent` actions.
|
||||
- Added a support widget to the bottom right of the screen.
|
||||
|
||||
#### @trigger.dev/sdk - v0.2.12
|
||||
|
||||
- Added `runOnce` and `runOnceLocalOnly` functions to support running custom idempotent actions. [Docs](/functions/run-once)
|
||||
- We will now serialize and send the Zod schemas for `customEvent` and `webhookEvent` to trigger.dev to support better test JSON generation (using `json-schema-faker`).
|
||||
|
||||
#### @trigger.dev/slack - v0.1.19
|
||||
|
||||
- Added support for opening modal views and handling view submissions. See [openView](/integrations/apis/slack/actions/open-view) and [viewSubmissionInteraction](/integrations/apis/slack/events/view-submission-interaction) docs for more info.
|
||||
- Added support for triggering on BlockKit actions and posting responses. See [blockActionInteraction](/integrations/apis/slack/events/block-action-interaction) and [postMessageResponse](/integrations/apis/slack/actions/post-message-response) docs for more info.
|
||||
- Added ability to add reactions to messages. See [addReaction](/integrations/apis/slack/actions/add-reaction) docs for more info.
|
||||
- You can now post a message in a thread using the `thread_ts` option in [postMessage](/integrations/apis/slack/actions/post-message).
|
||||
|
||||
#### @trigger.dev/whatsapp - v0.1.17
|
||||
|
||||
Initial release of our WhatsApp integration. Includes support for sending and receiving messages. See the [docs](/integrations/apis/whatsapp) for more info.
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
title: "Example workflows"
|
||||
sidebarTitle: "Overview"
|
||||
description: "Example workflows to use in your projects."
|
||||
---
|
||||
|
||||
Not sure what to build? Take a look through our examples for inspiration.
|
||||
You can use these workflows in your product by following the instructions on each page.
|
||||
|
||||
<CardGroup>
|
||||
<Card title="GitHub" icon="github" href="/examples/github">
|
||||
When a GitHub repo is starred, post information about the user to Slack
|
||||
</Card>
|
||||
<Card title="Shopify" icon="shopify" href="/examples/shopify">
|
||||
Create a new product in my Shopify store.
|
||||
</Card>
|
||||
<Card title="Slack" icon="slack" href="/examples/slack">
|
||||
Post to Slack when a GitHub issue is created or modified.
|
||||
</Card>
|
||||
<Card title="Resend" icon="envelope" href="/examples/resend">
|
||||
Create a welcome email drip campaign.
|
||||
</Card>
|
||||
<Card title="WhatsApp" icon="whatsapp" href="/examples/whatsapp">
|
||||
Listen for WhatsApp messages and reply.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,120 +0,0 @@
|
||||
---
|
||||
title: "GitHub"
|
||||
sidebarTitle: "GitHub"
|
||||
description: "Here are some example workflows you could create using the GitHub integration."
|
||||
---
|
||||
|
||||
You can explore all the supported GitHub functions [here](/integrations/apis/github/events/push).
|
||||
|
||||
### Example workflows:
|
||||
|
||||
## When a GitHub repo is starred, post information about the user to Slack
|
||||
|
||||
Integrations required: GitHub, Slack
|
||||
|
||||
Packages required:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install @trigger.dev/github @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @trigger.dev/github @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @trigger.dev/github @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Workflow code:
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
id: "new-github-star-to-slack",
|
||||
name: "New GitHub Star: triggerdotdev/trigger.dev",
|
||||
apiKey: "<my_api_key>",
|
||||
on: github.events.newStarEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event) => {
|
||||
await slack.postMessage("github-stars", {
|
||||
channelName: "github-stars",
|
||||
text: `New GitHub star from \n<${event.sender.html_url}|${event.sender.login}>`,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## When a GitHub issue is created or modified, post to Slack
|
||||
|
||||
Integrations required: GitHub, Slack
|
||||
|
||||
Packages required:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install @trigger.dev/github @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @trigger.dev/github @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @trigger.dev/github @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Workflow code:
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
id: "my-workflow-1",
|
||||
name: "Posts to Slack when GitHub Issue created or modified",
|
||||
apiKey: "<my_api_key>",
|
||||
on: github.events.issueEvent({
|
||||
repo: "my-github-org/my-github-repo",
|
||||
}),
|
||||
|
||||
run: async (event, ctx) => {
|
||||
const response = await slack.postMessage("send-to-slack", {
|
||||
channelName: "my-slack-channel-name",
|
||||
text: `A new issue has been created or modified. ${event.action}`,
|
||||
});
|
||||
|
||||
return response.message;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
You can explore all the supported GitHub functions [here](/integrations/apis/github/events/push).
|
||||
@@ -1,122 +0,0 @@
|
||||
---
|
||||
title: "Resend"
|
||||
sidebarTitle: "Resend"
|
||||
description: "Here are some example workflows you could create using the Resend integration."
|
||||
---
|
||||
|
||||
<Tip>
|
||||
Resend.com is currently in private beta but you can request early access
|
||||
[here](https://resend.com/).
|
||||
</Tip>
|
||||
|
||||
### Example workflows:
|
||||
|
||||
## Welcome email drip campaign
|
||||
|
||||
This workflow will get triggered and a Slack notification and welcome email will be sent straight away.
|
||||
1 day later we check if the user has completed onboarding, if they have, they get a 'tips' email, otherwise they get a re-engagement email.
|
||||
|
||||
Integrations required: Resend, Slack
|
||||
|
||||
Packages required:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install @trigger.dev/resend @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @trigger.dev/resend @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @trigger.dev/resend @trigger.dev/slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Workflow code:
|
||||
|
||||
```ts
|
||||
import { customEvent, Trigger, sendEvent } from "@trigger.dev/sdk";
|
||||
import * as resend from "@trigger.dev/resend";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import React from "react";
|
||||
import { z } from "zod";
|
||||
import { getUser } from "../db";
|
||||
import { InactiveEmail, TipsEmail, WelcomeEmail } from "./email-templates";
|
||||
|
||||
new Trigger({
|
||||
id: "welcome-email-campaign",
|
||||
name: "Welcome email drip campaign",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({
|
||||
userId: z.string(),
|
||||
}),
|
||||
}),
|
||||
async run(event, context) {
|
||||
//get the user data from the database
|
||||
const user = await getUser(event.userId);
|
||||
|
||||
await slack.postMessage("send-to-slack", {
|
||||
channelName: "new-users",
|
||||
text: `New user signed up: ${user.name} (${user.email})`,
|
||||
});
|
||||
|
||||
//Send the first email
|
||||
const welcomeResponse = await resend.sendEmail("welcome-email", {
|
||||
from: "Trigger.dev <james@email.trigger.dev>",
|
||||
replyTo: "James <james@trigger.dev>",
|
||||
to: user.email,
|
||||
subject: "Welcome to Trigger.dev",
|
||||
react: <WelcomeEmail name={user.name} />,
|
||||
});
|
||||
await context.logger.debug(
|
||||
`Sent welcome email to ${welcomeResponse.to} with id ${welcomeResponse.id}`
|
||||
);
|
||||
|
||||
//wait 1 day, check if the user has created a workflow and send the appropriate email
|
||||
await context.waitFor("wait-a-while", { days: 1 });
|
||||
const updatedUser = await getUser(event.userId);
|
||||
|
||||
if (updatedUser.hasOnboarded) {
|
||||
await resend.sendEmail("onboarding-complete", {
|
||||
from: "Trigger.dev <james@email.trigger.dev>",
|
||||
replyTo: "James <james@trigger.dev>",
|
||||
to: updatedUser.email,
|
||||
subject: "Pro tips for workflows",
|
||||
react: <TipsEmail name={updatedUser.name} />,
|
||||
});
|
||||
} else {
|
||||
await resend.sendEmail("onboarding-incomplete", {
|
||||
from: "Trigger.dev <james@email.trigger.dev>",
|
||||
replyTo: "James <james@trigger.dev>",
|
||||
to: updatedUser.email,
|
||||
subject: "Help with your first workflow",
|
||||
react: <InactiveEmail name={updatedUser.name} />,
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
<iframe
|
||||
width="100%"
|
||||
height="440"
|
||||
src="https://www.youtube.com/embed/aFlwD0frvnQ?rel=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
@@ -1,235 +0,0 @@
|
||||
---
|
||||
title: "Shopify"
|
||||
sidebarTitle: "Shopify"
|
||||
description: "Here are some example workflows you could create using the Shopify integration."
|
||||
---
|
||||
|
||||
### Example workflows:
|
||||
|
||||
## Create a new product
|
||||
|
||||
Integrations required: Shopify
|
||||
|
||||
Packages required:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install @trigger.dev/shopify
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @trigger.dev/shopify
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @trigger.dev/shopify
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Workflow code:
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import { z } from "zod";
|
||||
import * as shopify from "@trigger.dev/shopify";
|
||||
|
||||
new Trigger({
|
||||
id: "shopify-products",
|
||||
name: "Shopify products",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "shopify.products",
|
||||
schema: z.object({}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const newProduct = await shopify.createProduct("create-product", {
|
||||
descriptionHtml: "This is my brilliant <i>product description</i>.",
|
||||
title: `Fantastic product ${Math.floor(Math.random() * 1000)}`,
|
||||
productType: "t-shirt",
|
||||
vendor: "Nike",
|
||||
options: ["Color", "Size"],
|
||||
standardizedProductType: {
|
||||
productTaxonomyNodeId: "gid://shopify/ProductTaxonomyNode/352",
|
||||
},
|
||||
variants: [
|
||||
{
|
||||
price: "99.99",
|
||||
sku: "variant-1",
|
||||
inventoryItem: {
|
||||
tracked: true,
|
||||
},
|
||||
inventoryQuantities: [
|
||||
{
|
||||
availableQuantity: 1,
|
||||
locationId: "gid://shopify/Location/76187369773",
|
||||
},
|
||||
],
|
||||
options: ["Maroon", "Tiny"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const newImages = await shopify.appendProductImages("append-images", {
|
||||
id: newProduct.id,
|
||||
images: [
|
||||
{
|
||||
src: "https://via.placeholder.com/600/92c952.png",
|
||||
altText: "Image 1",
|
||||
},
|
||||
{
|
||||
src: "https://via.placeholder.com/600/d32776.png",
|
||||
altText: "Image 2",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return newProduct;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Update a product
|
||||
|
||||
Integrations required: Shopify
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import { z } from "zod";
|
||||
import * as shopify from "@trigger.dev/shopify";
|
||||
|
||||
new Trigger({
|
||||
id: "shopify-update-product",
|
||||
name: "Shopify update product",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "product.update",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const product = await shopify.updateProduct("update-product", {
|
||||
id: event.id,
|
||||
descriptionHtml: `<h1>Awesome product title</h1><p>With incredible description</p>`,
|
||||
});
|
||||
|
||||
return product;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Add a product to a collection
|
||||
|
||||
Integrations required: Shopify
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import { z } from "zod";
|
||||
import * as shopify from "@trigger.dev/shopify";
|
||||
|
||||
new Trigger({
|
||||
id: "shopify-add-product-to-collection",
|
||||
name: "Shopify add product to collection",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "product.new",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const collection = await shopify.addProductsToCollection(
|
||||
"add-products-to-collection",
|
||||
{
|
||||
collectionId: "gid://shopify/Collection/431864578349",
|
||||
productIds: [event.id],
|
||||
}
|
||||
);
|
||||
|
||||
return collection;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Create new product variants with images
|
||||
|
||||
Integrations required: Shopify
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import { z } from "zod";
|
||||
import * as shopify from "@trigger.dev/shopify";
|
||||
|
||||
const sizes = ["Small", "Medium", "Large"];
|
||||
const colors = [
|
||||
"Red",
|
||||
"Orange",
|
||||
"Yellow",
|
||||
"Green",
|
||||
"Blue",
|
||||
"Purple",
|
||||
"Pink",
|
||||
"Brown",
|
||||
"Black",
|
||||
"White",
|
||||
"Gray",
|
||||
"Silver",
|
||||
"Gold",
|
||||
"Beige",
|
||||
];
|
||||
const materials = ["Cotton", "Polyester", "Lycra", "Wool", "Silk", "Leather"];
|
||||
|
||||
function pickRandom(array: string[]): string {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
|
||||
new Trigger({
|
||||
id: "shopify-product-variants",
|
||||
name: "Shopify product variants",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "shopify.product-variants",
|
||||
schema: z.object({}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("Get Shopify products variants");
|
||||
|
||||
const results = await shopify.searchProductVariants(
|
||||
"get-shopify-variants",
|
||||
{
|
||||
filter: {
|
||||
productId: ["gid://shopify/Product/8098295546157"],
|
||||
sku: ["variant-1"],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const newVariant = await shopify.createProductVariant("create-variant", {
|
||||
productId: results.productVariants[0].product.id,
|
||||
inventoryQuantities: [
|
||||
{
|
||||
availableQuantity: 10,
|
||||
locationId: "gid://shopify/Location/76187369773",
|
||||
},
|
||||
],
|
||||
price: "12.34",
|
||||
sku: `variant-${Math.floor(Math.random() * 1000)}`,
|
||||
options: [pickRandom(sizes), pickRandom(materials)],
|
||||
});
|
||||
|
||||
await ctx.logger.debug("Debug message");
|
||||
|
||||
return newVariant;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
@@ -1,63 +0,0 @@
|
||||
---
|
||||
title: "Slack"
|
||||
sidebarTitle: "Slack"
|
||||
description: "Here are some example workflows you could create using the Slack integration."
|
||||
---
|
||||
|
||||
### Example workflows:
|
||||
|
||||
## Post to Slack when a GitHub issue is created or modified
|
||||
|
||||
Integrations required: Slack, GitHub
|
||||
|
||||
Packages required:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install @trigger.dev/slack @trigger.dev/github
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @trigger.dev/slack @trigger.dev/github
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @trigger.dev/slack @trigger.dev/github
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Workflow code:
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import { z } from "zod";
|
||||
|
||||
new Trigger({
|
||||
id: "my-workflow-1",
|
||||
name: "Posts to Slack when GitHub Issue created or modified",
|
||||
apiKey: "<my_api_key>",
|
||||
on: github.events.issueEvent({
|
||||
repo: "my-github-org/my-github-repo",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const response = await slack.postMessage("send-to-slack", {
|
||||
channelName: "my-slack-channel-name",
|
||||
text: `A new issue has been created or modified. ${event.action}`,
|
||||
});
|
||||
|
||||
return response.message;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
---
|
||||
title: "WhatsApp"
|
||||
sidebarTitle: "WhatsApp"
|
||||
description: "Here are some example workflows you could create using the WhatsApp integration."
|
||||
---
|
||||
|
||||
For more information about the WhatsApp integration, check out the [integration page](/integrations/apis/whatsapp).
|
||||
|
||||
### Example workflows:
|
||||
|
||||
## Listen for WhatsApp messages and reply
|
||||
|
||||
Integrations required: WhatsApp
|
||||
|
||||
Packages required:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install @trigger.dev/whatsapp
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @trigger.dev/whatsapp
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @trigger.dev/whatsapp
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Workflow code:
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendReaction, sendText } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "whatsapp-webhook",
|
||||
name: "Listen for WhatsApp messages and reply",
|
||||
apiKey: "<my_api_key>",
|
||||
//this listens for all WhatsApp messages sent to your WhatsApp Business account
|
||||
on: events.messageEvent({
|
||||
accountId: "<your_account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//these logs will appear on the run page
|
||||
await ctx.logger.info(`Message data`, event.message);
|
||||
await ctx.logger.info(`Phone number`, event.contacts[0]);
|
||||
|
||||
//add a 🥰 reaction to the original message
|
||||
const reactionResponse = await sendReaction("reaction", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
isReplyTo: event.message.id,
|
||||
emoji: "🥰",
|
||||
});
|
||||
|
||||
//send a text message in response
|
||||
const textResponse = await sendText("text-msg", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
text: "Hello! This is a text sent automatically from https://www.trigger.dev",
|
||||
});
|
||||
|
||||
//we support all other types of WhatsApp messages (audio, video, document, location, etc)
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
@@ -1,91 +0,0 @@
|
||||
---
|
||||
title: "Delays"
|
||||
sidebarTitle: "Delays"
|
||||
description: "You can trigger workflow steps to fire before and after a delay. There are 2 types of delay, waitFor and waitUntil."
|
||||
---
|
||||
|
||||
## `waitFor` delay
|
||||
|
||||
`waitFor` takes a unique key and an object that sets the desired time as a key value pair.
|
||||
|
||||
```ts
|
||||
await ctx.waitFor("wait-for-1", { seconds: 30 });
|
||||
```
|
||||
|
||||
<Note>Reminder: Ensure all keys are unique across all triggers.</Note>
|
||||
|
||||
### Example
|
||||
|
||||
This example posts a message to Slack after a 30 second delay:
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import { z } from "zod";
|
||||
|
||||
new Trigger({
|
||||
id: "wait-for-example",
|
||||
name: "Post to Slack after delay",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "waitForExample",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.waitFor("initial-wait", { seconds: 30 });
|
||||
|
||||
const response = await slack.postMessage("send-to-slack", {
|
||||
channel: "my-slack-channel",
|
||||
text: `This message posted after a 30 second delay.`,
|
||||
});
|
||||
|
||||
return response.message;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## `waitUntil` delay
|
||||
|
||||
`waitUntil` takes a unique key and a date function to set desired time.
|
||||
|
||||
```ts
|
||||
await ctx.waitUntil("wait-until-1", new Date(Date.now() + 1000 * 60 * 1));
|
||||
```
|
||||
|
||||
<Note>Reminder: Ensure all keys are unique across all triggers.</Note>
|
||||
|
||||
### Example
|
||||
|
||||
This example posts a message to Slack 1 hour after the workflow triggers:
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import { z } from "zod";
|
||||
|
||||
new Trigger({
|
||||
id: "wait-until-example",
|
||||
name: "Post to Slack after 1hr delay",
|
||||
apiKey: "<my_api_key>",
|
||||
on: customEvent({
|
||||
name: "waitUntilExample",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.waitUntil("wait-until", new Date(Date.now() + 1000 * 60 * 1));
|
||||
|
||||
const response = await slack.postMessage("send-to-slack", {
|
||||
channel: "my-slack-channel",
|
||||
text: `This message posted after a 30 second delay.`,
|
||||
});
|
||||
|
||||
return response.message;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
@@ -1,257 +0,0 @@
|
||||
---
|
||||
title: "Generic Fetch"
|
||||
sidebarTitle: "Fetch"
|
||||
description: "A generic fetch function that can be used to call any HTTP endpoint"
|
||||
---
|
||||
|
||||
## Why use our fetch?
|
||||
|
||||
The `fetch` function provided by the trigger.dev SDK is a generic function that can be used to call any HTTP endpoint. It is designed to be used inside a `Trigger.run` function, and gives you the following benefits over using the standard [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) API:
|
||||
|
||||
- We automatically retry with exponential back off (this can be configured with the options param)
|
||||
- The request and response are displayed in your Trigger.dev run dashbaord for easy debugging
|
||||
- We automatically parse the response body as JSON and provide it as `body` on the response (and typed if you give provide a [responseSchema](/#response))
|
||||
- We will retry the request reliably, even if your workflow is stopped, e.g. you deploy in the middle of a run. See [Resumability](/guides/resumability) for more information.
|
||||
|
||||
## Usage
|
||||
|
||||
A `fetch` function is available to use inside a `Trigger.run` function through the `context` argument, and should be familiar for anyone who has used the standard [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) API, with a few modifications.
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "fetch-example",
|
||||
name: "Fetch Example",
|
||||
on: customEvent({
|
||||
name: "example.fetch",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.fetch("Example Key", "http://httpbin.org/get");
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
Notice the first parameter to `fetch` is a `key` that is used to identify this call to fetch to support resumability. Please see the [Resumability](/guides/resumability) guide for more information.
|
||||
|
||||
You can also import `fetch` and use it outside of a `Trigger.run` function:
|
||||
|
||||
```ts httpBin.ts
|
||||
import { fetch } from "@trigger.dev/sdk";
|
||||
|
||||
export function httpBinGet() {
|
||||
return fetch("Example Key", "http://httpbin.org/get");
|
||||
}
|
||||
```
|
||||
|
||||
Now you can use the exported `httpBinGet` function inside your `Trigger.run` function:
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { httpBinGet } from "./httpBin";
|
||||
|
||||
new Trigger({
|
||||
id: "fetch-example",
|
||||
name: "Fetch Example",
|
||||
on: customEvent({
|
||||
name: "example.fetch",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await httpBinGet();
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
This is useful if you want to wrap `fetch` to provide an SDK like experience inside your workflows.
|
||||
|
||||
<Warning>
|
||||
Calling `fetch` when not inside of a workflow run will result in a thrown
|
||||
Error.
|
||||
</Warning>
|
||||
|
||||
## Response
|
||||
|
||||
<Tip>
|
||||
Make sure to check `response.ok`, as non-2xx status codes will not throw an
|
||||
error and will instead return a response with `ok` set to `false`.
|
||||
</Tip>
|
||||
|
||||
The return value of `fetch` is a similar to a normal fetch response, but we will automatically parse the response body as JSON and provide it as `body`, like so:
|
||||
|
||||
```ts
|
||||
const response = await ctx.fetch("Example Key", "http://httpbin.org/get");
|
||||
|
||||
if (response.body) {
|
||||
console.log(response.body.url); // http://httpbin.org/get
|
||||
}
|
||||
```
|
||||
|
||||
By default, the `body` is typed as `any`, but you can provide a [Zod](/guides/zod) schema to validate the response body and get a more specific type:
|
||||
|
||||
```ts
|
||||
import { z } from "zod";
|
||||
|
||||
const response = await ctx.fetch("Get HTTPBin", "http://httpbin.org/get", {
|
||||
responseSchema: z.object({
|
||||
url: z.string(),
|
||||
origin: z.string(),
|
||||
headers: z.record(z.string()),
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
Now the `body` will be typed as:
|
||||
|
||||
```ts
|
||||
{
|
||||
url: string;
|
||||
origin: string;
|
||||
headers: Record<string, string>;
|
||||
}
|
||||
```
|
||||
|
||||
It's okay to not be comprehensive with the schema, as long as the response body matches the schema, it will be valid. Do note that any properties not included in the schema will be excluded, unless you use `.passthrough()`:
|
||||
|
||||
```ts
|
||||
const response = await ctx.fetch("Get HTTPBin", "http://httpbin.org/get", {
|
||||
responseSchema: z.object({
|
||||
url: z.string(),
|
||||
origin: z.string(),
|
||||
headers: z.record(z.string()),
|
||||
}),
|
||||
});
|
||||
|
||||
console.log(response.body); // Only includes url, origin, and headers
|
||||
|
||||
// Using passthrough():
|
||||
const response = await ctx.fetch("Get HTTPBin", "http://httpbin.org/get", {
|
||||
responseSchema: z
|
||||
.object({
|
||||
url: z.string(),
|
||||
origin: z.string(),
|
||||
headers: z.record(z.string()),
|
||||
})
|
||||
.passthrough(),
|
||||
});
|
||||
|
||||
console.log(response.body); // Includes url, origin, headers, and everything else
|
||||
```
|
||||
|
||||
<Note>
|
||||
The fetch function currently only supports JSON request and response bodies.
|
||||
</Note>
|
||||
|
||||
## Secret values
|
||||
|
||||
If you are using a header with a secret value, you can use our `secureString` [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) to ensure that the value is not logged in the trigger.dev logs:
|
||||
|
||||
```ts
|
||||
import { Trigger, secureString } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "fetch-example",
|
||||
name: "Fetch Example",
|
||||
on: customEvent({
|
||||
name: "example.fetch",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.fetch("🔑 Secret API", "http://httpbin.org/post", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: secureString`Bearer ${process.env.SECRET_API_KEY}`,
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
Which will show in the trigger.dev app as:
|
||||
|
||||

|
||||
|
||||
## Retrying
|
||||
|
||||
By default, we will retry a failed request up to 10 times if it has one of the following status codes: `408`, `429`, `500`, `502`, `503`, `504`. You can override this behavior by providing a `retry` option:
|
||||
|
||||
```ts
|
||||
await ctx.fetch("Example Key", "http://httpbin.org/get", {
|
||||
retry: {
|
||||
maxAttempts: 5,
|
||||
statusCodes: [408, 429, 500, 502, 503, 504, 521, 522, 524],
|
||||
minTimeout: 1000,
|
||||
maxTimeout: 10000,
|
||||
factor: 1.2,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
| Property | Description | Default |
|
||||
| ----------- | ---------------------------------------- | ---------------------------------------- |
|
||||
| enabled | Enables retrying of failed requests | true |
|
||||
| factor | The exponential factor of backoff | 1.8 |
|
||||
| minTimeout | The minimum amount of ms between retries | 1000 |
|
||||
| maxTimeout | The maximum amount of ms between retries | 60000 |
|
||||
| statusCodes | The HTTP Status Codes that are retryable | `408`, `429`, `500`, `502`, `503`, `504` |
|
||||
|
||||
If you'd like to disable retrying, simple pass in the `retry` option with `enabled` set to `false`:
|
||||
|
||||
```ts
|
||||
await ctx.fetch("Example Key", "http://httpbin.org/get", {
|
||||
retry: {
|
||||
enabled: false,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="url" type="string | URL" required={true}>
|
||||
The URL to fetch.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="options" type="object" required={false}>
|
||||
<Expandable title="properties">
|
||||
<ParamField path="method" type="string" required={false}>
|
||||
The HTTP method to use. Defaults to `GET`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="headers" type="record" required={false}>
|
||||
An object of headers to send with the request.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="responseSchema" type="zod Schema" required={false}>
|
||||
A [Zod](/guides/zod) schema to validate the response body.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="body" type="json" required={false}>
|
||||
The body to send with the request. Only valid for `POST`, `PUT`, and `PATCH`. You don't need to `JSON.stringify` before passing it in.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ParamField path="ok" type="boolean">
|
||||
Whether the response was successful. Non-2xx status codes will have `ok =
|
||||
false`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="body" type="object" required={false}>
|
||||
The response body, parsed with the `responseSchema` if provided. Can be
|
||||
undefined if the response body is empty.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="status" type="number">
|
||||
The HTTP status code.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="headers" type="Record<string, string>">
|
||||
The response headers.
|
||||
</ParamField>
|
||||
@@ -1,41 +0,0 @@
|
||||
---
|
||||
title: "Logging"
|
||||
sidebarTitle: "Logging"
|
||||
description: "There are 4 different types of logs you can add as workflow steps."
|
||||
---
|
||||
|
||||
If you'd like to add additional logging to your workflow run, you can use our built-in logging utility
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "my-trigger",
|
||||
on: scheduleEvent({ rateOf: { minutes: 5 } }),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("It's been 5 minutes since the last run!");
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
This will log the message to your workflow run page in the Trigger dashboard
|
||||
|
||||
There are 4 different types of logs you can add as workflow steps:
|
||||
|
||||
```ts
|
||||
await ctx.logger.info("It's been 5 minutes since the last run!");
|
||||
await ctx.logger.debug("This is a debug log");
|
||||
await ctx.logger.warn("This is a warning");
|
||||
await ctx.logger.error("This is an error");
|
||||
```
|
||||
|
||||
You can also include a second argument to the logger to add additional metadata to the log:
|
||||
|
||||
```ts
|
||||
await ctx.logger.info("It's been 5 minutes since the last run!", {
|
||||
foo: "bar",
|
||||
baz: 123,
|
||||
});
|
||||
```
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
title: "Loops, Conditionals…"
|
||||
sidebarTitle: "Loops, Conditionals…"
|
||||
description: "Write any type of code."
|
||||
---
|
||||
|
||||
Currently, we don't have anything special for loops or conditionals. You can just write plain-old TypeScript code and it will Just Work™.
|
||||
|
||||
## Loops
|
||||
|
||||
When you perform an action (sendEvent, delays, etc.) inside of a loop, make sure to create unique keys for each action to make sure that your workflows are [Resumable](/guides/resumability):
|
||||
|
||||
```ts
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await ctx.waitFor(`Wait ${i}`, { seconds: 30 });
|
||||
|
||||
await slack.postMessage(`⭐️ New Star ${i}`, {
|
||||
channelName: "github-stars",
|
||||
text: `@${starredBy} just starred ${repoName}!`,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Parallel Execution
|
||||
|
||||
You can run actions in parallel using `Promise.all`, like so:
|
||||
|
||||
```ts
|
||||
await Promise.all(
|
||||
messages.map((message) =>
|
||||
slack.postMessage(message.id, {
|
||||
channelName: "github-stars",
|
||||
text: message.text,
|
||||
})
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
## Conditionals
|
||||
|
||||
You can use `if` statements to conditionally execute code, just like normal code:
|
||||
|
||||
```ts
|
||||
if (ctx.event.payload.action === "opened") {
|
||||
await slack.postMessage("New Issue", {
|
||||
channelName: "github-issues",
|
||||
text: `@${ctx.event.payload.sender.login} just opened an issue!`,
|
||||
});
|
||||
}
|
||||
```
|
||||
@@ -1,152 +0,0 @@
|
||||
---
|
||||
title: "Run Once"
|
||||
sidebarTitle: "Run Once"
|
||||
description: "Perform an action only once per run, even if your server is restarted."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
A `runOnce` function is available to use inside a `Trigger.run` function through the `context` argument, allowing you to run a callback function only once [\*](#caveats) per run, based on the key you provide. This makes it so you can write code that participates in the Trigger.dev resumability system, even if your server is restarted.
|
||||
|
||||
<Note>
|
||||
Please see our detailed [Keys and Resumability guide](/guides/resumability)
|
||||
for more information on how Trigger.dev handles resumability.
|
||||
</Note>
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "run-once-example",
|
||||
name: "Run Once Example",
|
||||
on: customEvent({
|
||||
name: "example.runOnce",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.runOnce("Example Key", async (idempotencyKey) =>
|
||||
performIdempotentAction(idempotencyKey)
|
||||
);
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
The `performIdempotentAction` above is only called once [\*](#caveats) per run, even if the server is restarted. The `idempotencyKey` is a unique key that is generated for each run, and is used to ensure that the action is only performed once per run.
|
||||
|
||||
<Info>
|
||||
The Stripe API is a great example of an API that uses idempotency keys to
|
||||
ensure that an action is only performed once. You can read more about it in
|
||||
their [Idempotent Requests
|
||||
docs](https://stripe.com/docs/api/idempotent_requests)
|
||||
</Info>
|
||||
|
||||
Your callback can also optionally return a value, and that value will be returned from the `runOnce` function.
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "run-once-example",
|
||||
name: "Run Once Example",
|
||||
on: customEvent({
|
||||
name: "example.runOnce",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const output = await ctx.runOnce("Example Key", async (idempotencyKey) =>
|
||||
performIdempotentAction(idempotencyKey)
|
||||
);
|
||||
|
||||
// Do something with the output
|
||||
// ...
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
In your app.trigger.dev run dashboard we will also display the output of your `runOnce` function, so you can see what it returned easily:
|
||||
|
||||

|
||||
|
||||
## Caveats
|
||||
|
||||
As you may have noticed above, we've used cleverly placed asterisks above to signal that your callback passed to the `runOnce` function MAY actually be called more than once, in certain situations.
|
||||
|
||||
It's possible that in between us running the `runOnce` callback and attempting to send the result to trigger.dev, an issue occurs and we are unable to save the result. If this happens, and we [resume](/guides/resumability) the same run at a later time, your callback function will be called again (but with the same idempotency key).
|
||||
|
||||
This is why it's important that your callback function is truly idempotent. If you're not sure what that means, we recommend reading the [Stripe docs on idempotent requests](https://stripe.com/docs/api/idempotent_requests).
|
||||
|
||||
## Local Only
|
||||
|
||||
If you don't want to send the result of the `runOnce` callback to trigger.dev, you can alternatively use the `runOnceLocalOnly` function. This is useful if you want to use the `runOnce` functionality, but don't want to store the value in the Trigger.dev database.
|
||||
|
||||
<Warning>
|
||||
`runOnceLocalOnly` will ALWAYS call your callback function, so be extra sure
|
||||
your callback is truly idempotent. See below for more information.
|
||||
</Warning>
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "run-once-local-only-example",
|
||||
name: "Run Once Local Only Example",
|
||||
on: customEvent({
|
||||
name: "example.runOnce",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const output = await ctx.runOnceLocalOnly(
|
||||
"Example Key",
|
||||
async (idempotencyKey) => performIdempotentAction(idempotencyKey)
|
||||
);
|
||||
|
||||
// Do something with the output
|
||||
// ...
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Real World Example
|
||||
|
||||
Let's say you want to use the Stripe SDK to make an idempotent charge to a customer using trigger.dev. You can use the `runOnce` function to generate an `idempotencyKey` and pass it to the Stripe SDK, ensuring that the charge is only made once per run.
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import Stripe from "stripe";
|
||||
import z from "zod";
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
||||
apiVersion: "2020-08-27",
|
||||
});
|
||||
|
||||
new Trigger({
|
||||
id: "stripe-charge",
|
||||
name: "Stripe Charge",
|
||||
on: customEvent({
|
||||
name: "example.stripeCharge",
|
||||
schema: z.object({
|
||||
orderId: z.string(),
|
||||
customerId: z.string(),
|
||||
amount: z.number(),
|
||||
}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const { customerId, amount, orderId } = event.data;
|
||||
|
||||
const stripeResponse = await ctx.runOnce(
|
||||
orderId,
|
||||
async (idempotencyKey) => {
|
||||
return await stripe.charges.create(
|
||||
{
|
||||
amount,
|
||||
currency: "usd",
|
||||
customer: customerId,
|
||||
},
|
||||
{
|
||||
idempotencyKey,
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return stripeResponse;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
@@ -1,201 +0,0 @@
|
||||
---
|
||||
title: "Send event"
|
||||
sidebarTitle: "Send event"
|
||||
description: "Send events to trigger your custom events workflows."
|
||||
---
|
||||
|
||||
## Send an event
|
||||
|
||||
You can easily send an event from anywhere, including from inside another workflow. Events don't have to come from the same server as your workflow and can be sent as HTTP requests from any language (see our cURL example below for the format).
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Our Node.js SDK">
|
||||
|
||||
```ts
|
||||
import { sendEvent } from "@trigger.dev/sdk";
|
||||
|
||||
//send an event with the name "user.created"
|
||||
//and the payload
|
||||
await sendEvent("start-fire-2", {
|
||||
name: "user.created",
|
||||
payload: { userId: "123456" },
|
||||
});
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="cURL">
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url https://app.trigger.dev/api/v1/events \
|
||||
--header 'Authorization: Bearer <insert_api_key_here>' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"id": "<optional unique event id>",
|
||||
"event": {
|
||||
"name": "user.created",
|
||||
"payload": {
|
||||
"userId": "123456"
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
If you are calling this from inside a workflow, ensure that the first parameter is unique inside your workflow.
|
||||
|
||||
## Sending events from other workflows
|
||||
|
||||
It is useful to send events from workflows because you can split your logic into smaller chunks and reuse them. The below example shows how a scheduled workflow delegates the work via sending a custom event:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts check-scheduler.ts
|
||||
new Trigger({
|
||||
id: "check-scheduler",
|
||||
name: "Check Scheduler",
|
||||
on: scheduleEvent({ rateOf: { minutes: 10 } }),
|
||||
run: async (event, context) => {
|
||||
await context.sendEvent("health.check trigger.dev", {
|
||||
name: "health.check",
|
||||
payload: {
|
||||
url: "https://trigger.dev",
|
||||
host: "trigger.dev",
|
||||
},
|
||||
});
|
||||
|
||||
await context.sendEvent("health.check docs.trigger.dev", {
|
||||
name: "health.check",
|
||||
payload: {
|
||||
url: "https://docs.trigger.dev",
|
||||
host: "docs.trigger.dev",
|
||||
},
|
||||
});
|
||||
|
||||
await context.sendEvent("health.check app.trigger.dev", {
|
||||
name: "health.check",
|
||||
payload: {
|
||||
url: "https://app.trigger.dev/healthcheck",
|
||||
host: "app.trigger.dev",
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```ts health-check.ts
|
||||
export const healthCheck = new Trigger({
|
||||
id: "health-check",
|
||||
name: "Health Check",
|
||||
on: customEvent({
|
||||
name: "health.check",
|
||||
schema: z.object({
|
||||
url: z.string().url(),
|
||||
host: z.string(),
|
||||
}),
|
||||
}),
|
||||
run: async (event, context) => {
|
||||
const response = await context.fetch("fetch site", event.url, {
|
||||
method: "GET",
|
||||
retry: {
|
||||
enabled: false,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await context.logger.info(`${event.host} is up!`);
|
||||
return;
|
||||
}
|
||||
|
||||
await slack.postMessage("Site is down", {
|
||||
channelName: "health-checks",
|
||||
text: `${event.host} is down: ${response.status}`,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Delaying event delivery
|
||||
|
||||
Through both our Node.js SDK and our HTTP API, you can delay the delivery of an event. This is useful if you want to send an event to trigger a workflow, but you want to wait for a certain amount of time before the event is delivered.
|
||||
|
||||
Using the health check example above, we can delay the delivery of the `health.check` event in various ways:
|
||||
|
||||
```ts
|
||||
new Trigger({
|
||||
id: "check-scheduler",
|
||||
name: "Check Scheduler",
|
||||
on: scheduleEvent({ rateOf: { minutes: 10 } }),
|
||||
run: async (event, context) => {
|
||||
await context.sendEvent("health.check trigger.dev", {
|
||||
name: "health.check",
|
||||
payload: {
|
||||
url: "https://trigger.dev",
|
||||
host: "trigger.dev",
|
||||
},
|
||||
delay: { until: new Date(Date.now() + 1000 * 60 * 5) }, // Delay until a specific date
|
||||
});
|
||||
|
||||
await context.sendEvent("health.check docs.trigger.dev", {
|
||||
name: "health.check",
|
||||
payload: {
|
||||
url: "https://docs.trigger.dev",
|
||||
host: "docs.trigger.dev",
|
||||
},
|
||||
delay: { minutes: 5 }, // Delay for a specific amount of time
|
||||
});
|
||||
|
||||
await context.sendEvent("health.check app.trigger.dev", {
|
||||
name: "health.check",
|
||||
payload: {
|
||||
url: "https://app.trigger.dev/healthcheck",
|
||||
host: "app.trigger.dev",
|
||||
},
|
||||
delay: { seconds: 30 }, // Delay for a specific amount of time
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
<Note>
|
||||
When sending events in the context of a workflow run, adding a delay DOES NOT
|
||||
add a delay to the workflow run, as sending a custom event is a
|
||||
fire-and-forget action.
|
||||
</Note>
|
||||
|
||||
You can add delays via the HTTP API by adding a `delay` object to the event:
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url https://app.trigger.dev/api/v1/events \
|
||||
--header 'Authorization: Bearer <insert_api_key_here>' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"id": "<optional unique event id>",
|
||||
"event": {
|
||||
"name": "user.created",
|
||||
"payload": {
|
||||
"userId": "123456"
|
||||
},
|
||||
"delay": {
|
||||
"seconds": 30
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
## Event deduplication
|
||||
|
||||
When sending events, you can specify an `id` for the event. If you send an event with the same `id` multiple times, only the first event will be delivered. This is useful if you want to ensure that an event is only delivered once, even if you send it multiple times.
|
||||
|
||||
```ts
|
||||
sendEvent({
|
||||
id: "my-event-id",
|
||||
name: "my-event",
|
||||
payload: { foo: "bar" },
|
||||
});
|
||||
```
|
||||
@@ -1,239 +0,0 @@
|
||||
---
|
||||
title: "Getting started with Trigger.dev"
|
||||
sidebarTitle: "Quick start"
|
||||
description: "Get your first workflow running in just a few minutes"
|
||||
---
|
||||
|
||||
Trigger.dev workflows are written in your codebase and run in your existing infrastructure. This means:
|
||||
|
||||
- They are version controlled with the rest of your code.
|
||||
- They run locally and don't require you to use tunnels.
|
||||
|
||||
<Note>
|
||||
Currently we require you to have a long-running Node.js server, e.g. Express.
|
||||
Support for serverless is coming soon.
|
||||
</Note>
|
||||
|
||||
## 1. Installing @trigger.dev packages
|
||||
|
||||
In your existing project install the packages:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install @trigger.dev/sdk @trigger.dev/slack zod
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add @trigger.dev/sdk @trigger.dev/slack zod
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add @trigger.dev/sdk @trigger.dev/slack zod
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
What do the packages do?
|
||||
|
||||
- `@trigger.dev/sdk` is required to use Trigger.dev, it allows you to run workflows.
|
||||
- `@trigger.dev/slack` is the official Slack integration, which allows you to interact with the Slack API.
|
||||
- `zod` is used to define schemas (the expected shape of an object).
|
||||
|
||||
## 2. Sign in to your Trigger.dev dashboard
|
||||
|
||||
Go to [trigger.dev](https://app.trigger.dev) and sign up or login to your account.
|
||||
|
||||
## 3. Get your API keys
|
||||
|
||||
In the bottom-left corner of an Organization page you can find your API keys.
|
||||

|
||||
|
||||
## 4. Creating your first workflow
|
||||
|
||||
Workflows are triggered by events. In this example, we have defined a custom event called `user.created`. We support many different types of events including webhooks, scheduled, and more coming soon.
|
||||
|
||||
```ts first-workflow.ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import { postMessage } from "@trigger.dev/slack";
|
||||
import { z } from "zod";
|
||||
|
||||
new Trigger({
|
||||
id: "new-user",
|
||||
name: "New user slack message",
|
||||
apiKey: "<your_api_key>",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
paidPlan: z.boolean(),
|
||||
}),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("This log will appear on the Trigger.dev run page");
|
||||
|
||||
//send a message to the #new-users Slack channel with user details
|
||||
const response = await postMessage("send-to-slack", {
|
||||
channel: "new-users",
|
||||
text: `New user: ${event.name} (${event.email}) signed up. ${
|
||||
event.paidPlan ? "They are paying" : "They are on the free plan"
|
||||
}.`,
|
||||
});
|
||||
|
||||
return response.message;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
You'll notice that when we subscribe to the custom event we have to say the name of the event and provide a schema. Schemas are created using Zod. In this case events must send an object that has `name`, `email`, and `paidPlan`.
|
||||
|
||||
<Note>
|
||||
If the event is triggered with an object that doesn't match this schema, the
|
||||
workflow won't run.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
Above we set the API key inside the Trigger object. We recommend instead that
|
||||
you add an environment variable called `TRIGGER_API_KEY`. That way you can use
|
||||
your development API key locally and the production one when you deploy.
|
||||
</Note>
|
||||
|
||||
## 6. Run your web server
|
||||
|
||||
Run your server how you normally would, e.g. `npm run dev`. This will connect your workflow to Trigger.dev, so we can start sending you events. You should see some log messages in your server console (tip: you can turn these off by removing the `logLevel: "info"` from the code above).
|
||||
|
||||
## 5. Testing your workflow from the dashboard
|
||||
|
||||
Now that the workflow is connected to Trigger.dev we need to trigger it. You can easily test your workflow from [your Trigger.dev dashboard](https://app.trigger.dev).
|
||||
|
||||
On the organization page you should see that the Workflow has now appeared (you may need to refresh the page from last time).
|
||||
|
||||

|
||||
|
||||
Move to the "New user slack message" and you will see the workflow page. There have been no runs yet.
|
||||
|
||||
Move to the "Test" page and input a valid test event, remember the workflow expects a name, email and paidPlan. You can copy this:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Rick Astley",
|
||||
"email": "nevergonn@giveyou.up",
|
||||
"paidPlan": true
|
||||
}
|
||||
```
|
||||
|
||||
Hit the "Run test" button and it will take us to our first run 🚀!
|
||||
|
||||

|
||||
|
||||
## 6. The run page
|
||||
|
||||
All of the steps in a workflow, including the initial event, can be viewed in detail. You will need to refresh the page if it's running to see it move between steps.
|
||||
|
||||
But there's a problem, we've used Slack in our code and we haven't authenticated.
|
||||
|
||||

|
||||
|
||||
## 7. Authenticating with Slack
|
||||
|
||||
When a workflow step uses an API integration that you haven't already authenticated with, it will pause until you've authenticated.
|
||||
|
||||
Simply click the "Connect to Slack" button and sign-in with your desired Slack workspace. As soon as you do, the workflow will pick up where it left off.
|
||||
|
||||
Test complete!
|
||||
|
||||

|
||||
|
||||
## 8. Triggering this workflow from code
|
||||
|
||||
As this workflow uses a custom event, we need to manually trigger it from our code. Anywhere in your code you can do this:
|
||||
|
||||
```ts
|
||||
import { sendEvent } from "@trigger.dev/sdk";
|
||||
|
||||
/*
|
||||
...your other code
|
||||
*/
|
||||
|
||||
await sendEvent(uuidv4(), {
|
||||
name: "user.created"
|
||||
payload: {
|
||||
name: "Eleven",
|
||||
email: "jane@hawksmoorhigh.edu",
|
||||
paidPlan: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
If you are using `sendEvent` outside of a Trigger, make sure and set your API
|
||||
key to the `TRIGGER_API_KEY` environment variable. See the
|
||||
[sendEvent](/functions/send-event) docs for more info.
|
||||
</Note>
|
||||
|
||||
When you run your server and this code executes, it will trigger the workflow. You will see this in the run list on your workflow page.
|
||||
|
||||
You can also use our API to send events from other programming languages. See the [sendEvent](/api/events/sendEvent) API reference for more info.
|
||||
|
||||
## Next steps
|
||||
|
||||
<Card
|
||||
title="Join the communty"
|
||||
icon="discord"
|
||||
href="https://discord.gg/nkqV9xBYWy"
|
||||
>
|
||||
Meet other users, get help and product updates. We will respond to all
|
||||
messages and will help with any issues.
|
||||
</Card>
|
||||
|
||||
There are many things we didn't cover here, including Webhook and Scheduled triggers. Below are a some more features to explore:
|
||||
|
||||
### Triggers
|
||||
|
||||
Triggers are what cause your workflows to run.
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Webhooks" icon="rectangle-terminal" href="/triggers/webhooks">
|
||||
Easily subscribe to the APIs you're using
|
||||
</Card>
|
||||
<Card title="Scheduled" icon="clock" href="/triggers/scheduled">
|
||||
Trigger your workflows on a repeating schedule
|
||||
</Card>
|
||||
<Card title="Custom events" icon="code" href="/triggers/custom-events">
|
||||
More details on custom events
|
||||
</Card>
|
||||
<Card title="More coming soon" icon="bookmark">
|
||||
On received email, HTTP endpoint and AWS Event Bridge
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### Functions
|
||||
|
||||
<CardGroup>
|
||||
<Card
|
||||
title="API integrations"
|
||||
icon="rectangle-terminal"
|
||||
href="/integrations/apis"
|
||||
>
|
||||
We are making it easy to use lots of APIs by adding integrations.
|
||||
</Card>
|
||||
<Card title="Fetch" icon="server" href="/functions/fetch">
|
||||
Call any API from your workflow
|
||||
</Card>
|
||||
<Card title="Delays" icon="alarm-clock" href="/functions/delays">
|
||||
Add delays to your workflows. They're resilient so it doesn't matter if your
|
||||
server goes down.
|
||||
</Card>
|
||||
<Card title="Send event" icon="code" href="/functions/send-event">
|
||||
Send an event, to trigger a custom event workflow
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,64 +0,0 @@
|
||||
---
|
||||
title: "Event Driven Architecture"
|
||||
sidebarTitle: "Event Driven"
|
||||
description: "How to build an event driven architecture using Trigger.dev"
|
||||
---
|
||||
|
||||
## Event-driven Patterns in Trigger.dev
|
||||
|
||||
### Claim check pattern
|
||||
|
||||
Inspired by [this post](https://serverlessland.com/event-driven-architecture/visuals/claim-check-pattern) by [@boyney123](https://twitter.com/boyney123), here is how you could implement the claim check pattern using Trigger.dev:
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import { db } from "./db.server";
|
||||
|
||||
new Trigger({
|
||||
id: "issue-producer",
|
||||
on: github.events.issueEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
// 1. Store the event in a database (e.g. MongoDB, DynamoDB, etc.)
|
||||
const id = await db.insert(ctx.id, event);
|
||||
|
||||
// 2. Send a new event with the id of the stored event
|
||||
await ctx.sendEvent("📧 Send Event", {
|
||||
name: "github.issue",
|
||||
payload: {
|
||||
id,
|
||||
action: event.payload.action,
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
The above workflow will store any issue events from the trigger.dev repo in a database. Then, it will send a new event with the name `github.issue` and the id and action of the stored event. This event can then trigger another workflow and be used to retrieve the original event from the database:
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import { db } from "./db.server";
|
||||
import { z } from "zod";
|
||||
|
||||
new Trigger({
|
||||
id: "opened-issue-consumer",
|
||||
on: customEvent({
|
||||
name: "github.issue",
|
||||
filter: {
|
||||
action: ["opened"],
|
||||
}
|
||||
schema: z.object({ id: z.string() }),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
// 3. Retrieve the event from the database
|
||||
const event = await db.get(ctx.id);
|
||||
|
||||
// 4. Do something with the event
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
As you can see above we filtered the event to only trigger when the action is `opened`. This is because we only want to do something when an issue is opened. We also used a schema to validate the event payload (which in this pattern is pretty simple).
|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: "Event Filters"
|
||||
sidebarTitle: "Event Filters"
|
||||
description: "Event filters are used to filter events based on their attributes."
|
||||
---
|
||||
|
||||
Event filters are used to filter events based on their attributes in the [customEvent](/reference/custom-event) and [webhookEvent](/reference/webhook-event) triggers.
|
||||
|
||||
They are declarative pattern-matching rules, modeled after [AWS EventBridge patterns](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html).
|
||||
|
||||
Given the following custom event payload:
|
||||
|
||||
```json
|
||||
{
|
||||
{
|
||||
"uid": "jexAgaeJFJsrGfans1pxqm",
|
||||
"type": "15 Min Meeting",
|
||||
"price": 0,
|
||||
"title": "15 Min Meeting between Eric Allam and John Doe",
|
||||
"length": 15,
|
||||
"status": "ACCEPTED",
|
||||
"endTime": "2023-01-25T16:00:00Z",
|
||||
"bookingId": 198052,
|
||||
"organizer": {
|
||||
"id": 32794,
|
||||
"name": "Eric Allam",
|
||||
"email": "eric@trigger.dev",
|
||||
"language": { "locale": "en" },
|
||||
"timeZone": "Europe/London"
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following event filter would match the event:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": ["15 Min Meeting"],
|
||||
"status": ["ACCEPTED", "REJECTED"],
|
||||
"organizer": {
|
||||
"name": ["Eric Allam"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For an event pattern to match an event, the event must contain all the field names listed in the event pattern. The field names must also appear in the event with the same nesting structure.
|
||||
|
||||
The value of each field name in the event pattern must be an array of strings, numbers, or booleans. The event pattern matches the event if the value of the field name in the event is equal to any of the values in the array.
|
||||
|
||||
Effectively, each array is an OR condition, and the entire event pattern is an AND condition.
|
||||
|
||||
So the above event filter will match because `status == "ACCEPTED"`, and it would also match if `status == "REJECTED"`.
|
||||
@@ -1,72 +0,0 @@
|
||||
---
|
||||
title: "Resumability"
|
||||
sidebarTitle: "Keys and Resumability"
|
||||
description: "Understand how keys work to ensure resumability of long-running workflows in Trigger.dev"
|
||||
---
|
||||
|
||||
## Intro
|
||||
|
||||
In this article, we'll cover how Trigger.dev handles resumability of long-running workflows. We'll also cover how to use keys to ensure that your workflows are resumable.
|
||||
|
||||
## What is resumability?
|
||||
|
||||
Resumability is the ability of a workflow run to continue from where it left off after a failure or interruption. For example, if a workflow run is interrupted due to a network failure, it should be able to resume from where it left off when the network is back up.
|
||||
|
||||
We accomplish this by storing the state of the workflow run in a database, and when a workflow run is resumed we will call the `Trigger.run` function again.
|
||||
|
||||
We use step "keys" to determine which steps have already been executed. If a step has already been executed, we will skip it and move on to the next step.
|
||||
|
||||
## How to use keys
|
||||
|
||||
Like we mentioned above, we use step keys to determine which steps have already been executed. They are defined by you inside your `Trigger.run` function, for example when you call `slack.postMessage`:
|
||||
|
||||
```ts
|
||||
await slack.postMessage("⭐️ New Star", {
|
||||
channelName: "github-stars",
|
||||
text: `@${starredBy} just starred ${repoName}!`,
|
||||
});
|
||||
```
|
||||
|
||||
In this example, the key is the string `"⭐️ New Star"`. This means that if the workflow is interrupted and then resumed, the `slack.postMessage` step will be skipped because it has already been executed.
|
||||
|
||||
If you make multiple calls to `slack.postMessage`, you should use different keys for each call. For example:
|
||||
|
||||
```ts
|
||||
await slack.postMessage("⭐️ New Star", {
|
||||
channelName: "github-stars",
|
||||
text: `@${starredBy} just starred ${repoName}!`,
|
||||
});
|
||||
|
||||
await slack.postMessage("🚨 Critical Issue", {
|
||||
channelName: "critical-issues",
|
||||
text: `@${assignee} just opened a critical issue in ${repoName}!`,
|
||||
});
|
||||
```
|
||||
|
||||
If you are calling a step multiple times with the same key, it will only be executed once. For example, if you call `slack.postMessage` with the key `"⭐️ New Star"` twice, it will only be executed once.
|
||||
|
||||
## How to use keys with loops
|
||||
|
||||
If you are using a loop, you should use the loop index as the key. For example:
|
||||
|
||||
```ts
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await ctx.waitFor(`Wait ${i}`, { seconds: 30 });
|
||||
|
||||
await slack.postMessage(`⭐️ New Star ${i}`, {
|
||||
channelName: "github-stars",
|
||||
text: `@${starredBy} just starred ${repoName}!`,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## When to use keys
|
||||
|
||||
The following functions in Trigger.dev require a `key` parameter:
|
||||
|
||||
- Integration actions (e.g. `slack.postMessage`)
|
||||
- [delays](/functions/delays)
|
||||
- [sendEvent](/functions/send-event)
|
||||
- [fetch](/functions/fetch)
|
||||
|
||||
[Logging](/functions/logging) does not require a key, as we are currently using the log message as the key.
|
||||
|
Before Width: | Height: | Size: 405 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 402 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 463 KiB |
|
Before Width: | Height: | Size: 346 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 360 KiB |
@@ -1,32 +0,0 @@
|
||||
---
|
||||
title: "APIs"
|
||||
sidebarTitle: "APIs"
|
||||
description: "Integrations"
|
||||
---
|
||||
|
||||
## Coming soon
|
||||
|
||||
We will show each API as a subpage. Each API page will break down all the functions available for each API. It will also link to the relevant sample projects.
|
||||
|
||||
<CardGroup>
|
||||
<Card
|
||||
title="GitHub"
|
||||
icon="rectangle-terminal"
|
||||
href="/integrations/apis/github"
|
||||
></Card>
|
||||
<Card
|
||||
title="Shopify"
|
||||
icon="rectangle-terminal"
|
||||
href="/integrations/apis/shopify"
|
||||
></Card>
|
||||
<Card
|
||||
title="Slack"
|
||||
icon="rectangle-terminal"
|
||||
href="/integrations/apis/slack"
|
||||
></Card>
|
||||
</CardGroup>
|
||||
|
||||
### Do you need a specific integration?
|
||||
|
||||
If so, [let us know](mailto:hello@trigger.dev) and we'll build it for
|
||||
you.
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
title: "GitHub"
|
||||
sidebarTitle: "GitHub"
|
||||
description: "Support for the GitHub API"
|
||||
---
|
||||
|
||||
## GitHub API integration
|
||||
|
||||
Full reference of all functions is coming soon.
|
||||
|
||||
Check out some example workflows using the GitHub API [here](/examples/github).
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
title: "GitHub Events"
|
||||
sidebarTitle: "Events"
|
||||
description: "GitHub Triggers"
|
||||
---
|
||||
|
||||
## GitHub API integration
|
||||
|
||||
Full reference of all functions is coming soon.
|
||||
|
||||
Check out some example workflows using the GitHub API [here](/examples/github).
|
||||
|
||||
### Events
|
||||
|
||||
These are the events you can use to trigger a workflow
|
||||
|
||||
### Requests
|
||||
|
||||
These are the requests you can make to the GitHub API.
|
||||
@@ -1,376 +0,0 @@
|
||||
---
|
||||
title: "Issue Comment Event"
|
||||
sidebarTitle: "Issue Comments"
|
||||
description: "Trigger a workflow whenever an issue_comment action is performed in a GitHub repository."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.issueCommentEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="repo" type="string" required={true}>
|
||||
The full path to the repository, including the organization
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="action" type="string">
|
||||
The issue_comment action, which can be either created, deleted, or edited.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="comment" type="object" required={true}>
|
||||
The comment object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="issue" type="object" required={true}>
|
||||
The issue object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="repository" type="object" required={true}>
|
||||
A repository on GitHub.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="sender" type="object" required={true}>
|
||||
The GitHub user object who performed the action.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="organization" type="object">
|
||||
The organization object the repository belongs to.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on new Issue comment
|
||||
new Trigger({
|
||||
id: "github-to-slack",
|
||||
name: "Notify Slack on new Issue comment",
|
||||
on: github.events.issueCommentEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (event.action === "created") {
|
||||
await slack.postMessage("New Comment", {
|
||||
channelName: "github-issues",
|
||||
text: `New comment on issue ${event.issue.title} by ${event.sender.login}: ${event.comment.html_url}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Event payload
|
||||
|
||||
```json
|
||||
{
|
||||
"issue": {
|
||||
"id": 1548436712,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/1",
|
||||
"body": "Changed the body text once",
|
||||
"user": {
|
||||
"id": 10635986,
|
||||
"url": "https://api.github.com/users/matt-aitken",
|
||||
"type": "User",
|
||||
"login": "matt-aitken",
|
||||
"node_id": "MDQ6VXNlcjEwNjM1OTg2",
|
||||
"html_url": "https://github.com/matt-aitken",
|
||||
"gists_url": "https://api.github.com/users/matt-aitken/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/matt-aitken/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10635986?v=4",
|
||||
"events_url": "https://api.github.com/users/matt-aitken/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/matt-aitken/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/matt-aitken/followers",
|
||||
"following_url": "https://api.github.com/users/matt-aitken/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/matt-aitken/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/matt-aitken/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/matt-aitken/received_events"
|
||||
},
|
||||
"state": "open",
|
||||
"title": "Changed test issue title",
|
||||
"labels": [
|
||||
{
|
||||
"id": 5003355458,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels/documentation",
|
||||
"name": "documentation",
|
||||
"color": "0075ca",
|
||||
"default": true,
|
||||
"node_id": "LA_kwDOIxVdCc8AAAABKjklQg",
|
||||
"description": "Improvements or additions to documentation"
|
||||
},
|
||||
{
|
||||
"id": 5003355474,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels/enhancement",
|
||||
"name": "enhancement",
|
||||
"color": "a2eeef",
|
||||
"default": true,
|
||||
"node_id": "LA_kwDOIxVdCc8AAAABKjklUg",
|
||||
"description": "New feature or request"
|
||||
}
|
||||
],
|
||||
"locked": false,
|
||||
"number": 1,
|
||||
"node_id": "I_kwDOIxVdCc5cS0To",
|
||||
"assignee": null,
|
||||
"comments": 6,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples/issues/1",
|
||||
"assignees": [],
|
||||
"closed_at": null,
|
||||
"milestone": {
|
||||
"id": 8941544,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones/1",
|
||||
"state": "open",
|
||||
"title": "Test milestone",
|
||||
"due_on": "2023-01-20T08:00:00Z",
|
||||
"number": 1,
|
||||
"creator": {
|
||||
"id": 10635986,
|
||||
"url": "https://api.github.com/users/matt-aitken",
|
||||
"type": "User",
|
||||
"login": "matt-aitken",
|
||||
"node_id": "MDQ6VXNlcjEwNjM1OTg2",
|
||||
"html_url": "https://github.com/matt-aitken",
|
||||
"gists_url": "https://api.github.com/users/matt-aitken/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/matt-aitken/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10635986?v=4",
|
||||
"events_url": "https://api.github.com/users/matt-aitken/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/matt-aitken/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/matt-aitken/followers",
|
||||
"following_url": "https://api.github.com/users/matt-aitken/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/matt-aitken/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/matt-aitken/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/matt-aitken/received_events"
|
||||
},
|
||||
"node_id": "MI_kwDOIxVdCc4AiG_o",
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples/milestone/1",
|
||||
"closed_at": null,
|
||||
"created_at": "2023-01-19T03:02:37Z",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones/1/labels",
|
||||
"updated_at": "2023-01-19T17:21:25Z",
|
||||
"description": "",
|
||||
"open_issues": 1,
|
||||
"closed_issues": 0
|
||||
},
|
||||
"reactions": {
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/1/reactions",
|
||||
"eyes": 0,
|
||||
"heart": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"rocket": 0,
|
||||
"confused": 0,
|
||||
"total_count": 0
|
||||
},
|
||||
"created_at": "2023-01-19T02:50:49Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/1/events",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/1/labels{/name}",
|
||||
"updated_at": "2023-01-24T04:18:52Z",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/1/comments",
|
||||
"state_reason": "reopened",
|
||||
"timeline_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/1/timeline",
|
||||
"repository_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"active_lock_reason": null,
|
||||
"author_association": "MEMBER",
|
||||
"performed_via_github_app": null
|
||||
},
|
||||
"action": "created",
|
||||
"sender": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"comment": {
|
||||
"id": 1401375866,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments/1401375866",
|
||||
"body": "New comment",
|
||||
"user": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"node_id": "IC_kwDOIxVdCc5Th0x6",
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples/issues/1#issuecomment-1401375866",
|
||||
"issue_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/1",
|
||||
"reactions": {
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments/1401375866/reactions",
|
||||
"eyes": 0,
|
||||
"heart": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"rocket": 0,
|
||||
"confused": 0,
|
||||
"total_count": 0
|
||||
},
|
||||
"created_at": "2023-01-24T04:18:52Z",
|
||||
"updated_at": "2023-01-24T04:18:52Z",
|
||||
"author_association": "MEMBER",
|
||||
"performed_via_github_app": null
|
||||
},
|
||||
"repository": {
|
||||
"id": 588602633,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": "2023-01-23T19:06:36Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": "2023-01-13T14:26:45Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 2,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 2,
|
||||
"web_commit_signoff_required": false
|
||||
},
|
||||
"organization": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/orgs/triggerdotdev",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"hooks_url": "https://api.github.com/orgs/triggerdotdev/hooks",
|
||||
"repos_url": "https://api.github.com/orgs/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/orgs/triggerdotdev/events",
|
||||
"issues_url": "https://api.github.com/orgs/triggerdotdev/issues",
|
||||
"description": "",
|
||||
"members_url": "https://api.github.com/orgs/triggerdotdev/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/triggerdotdev/public_members{/member}"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,428 +0,0 @@
|
||||
---
|
||||
title: "Issue Event"
|
||||
sidebarTitle: "Issues"
|
||||
description: "Trigger a workflow whenever an issue action is performed in a GitHub repository."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.issueEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="repo" type="string" required={true}>
|
||||
The full path to the repository, including the organization
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="action" type="string">
|
||||
The issue action, can be one of assigned, closed, deleted, edited, labeled,
|
||||
unlabeled, locked, opened, pinned, reopened, transferred, unlocked, or
|
||||
unassigned.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="issue" type="object" required={true}>
|
||||
The issue object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="repository" type="object" required={true}>
|
||||
A repository on GitHub.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="sender" type="object" required={true}>
|
||||
The GitHub user object who performed the action.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="organization" type="object">
|
||||
The organization object the repository belongs to.
|
||||
</ResponseField>
|
||||
|
||||
## Additional event fields
|
||||
|
||||
### transferred issues
|
||||
|
||||
<ResponseField name="changes" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="new_issue" type="object">
|
||||
The new issue object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="new_repository" type="object">
|
||||
The new issue repository.
|
||||
</ResponseField>
|
||||
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
### edited issues
|
||||
|
||||
<ResponseField name="changes" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="body" type="object">
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ResponseField name="from" type="string">
|
||||
The previous body text.
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="title" type="object">
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ResponseField name="from" type="string">
|
||||
The previous title text.
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
### labeled/unlabeled issues
|
||||
|
||||
<ResponseField name="label" type="object">
|
||||
The label object.
|
||||
</ResponseField>
|
||||
|
||||
### assigned/unassigned issues
|
||||
|
||||
<ResponseField name="assignee" type="object">
|
||||
The assignee object.
|
||||
</ResponseField>
|
||||
|
||||
### opened issues
|
||||
|
||||
<ResponseField name="changes" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="old_issue" type="object">
|
||||
The old issue object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="old_repository" type="object">
|
||||
The old issue repository.
|
||||
</ResponseField>
|
||||
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on Critical Issue
|
||||
new Trigger({
|
||||
id: "github-to-slack",
|
||||
name: "Notify of critical issues",
|
||||
on: github.events.issueEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (event.action === "labeled") {
|
||||
if (event.label?.name === "critical") {
|
||||
await slack.postMessage("send-to-slack", {
|
||||
channelName: "serious-issues",
|
||||
text: `Critical issue: ${event.issue.title} was labeled ${event.label.name}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Event payload
|
||||
|
||||
```json
|
||||
{
|
||||
"issue": {
|
||||
"id": 1514714160,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/2",
|
||||
"body": "This is the body text\r\n`const name = \"Matt\"`",
|
||||
"user": {
|
||||
"id": 10635986,
|
||||
"url": "https://api.github.com/users/matt-aitken",
|
||||
"type": "User",
|
||||
"login": "matt-aitken",
|
||||
"node_id": "MDQ6VXNlcjEwNjM1OTg2",
|
||||
"html_url": "https://github.com/matt-aitken",
|
||||
"gists_url": "https://api.github.com/users/matt-aitken/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/matt-aitken/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10635986?v=4",
|
||||
"events_url": "https://api.github.com/users/matt-aitken/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/matt-aitken/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/matt-aitken/followers",
|
||||
"following_url": "https://api.github.com/users/matt-aitken/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/matt-aitken/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/matt-aitken/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/matt-aitken/received_events"
|
||||
},
|
||||
"state": "open",
|
||||
"title": "Test issue for webhook",
|
||||
"labels": [
|
||||
{
|
||||
"id": 4858587614,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev/labels/documentation",
|
||||
"name": "documentation",
|
||||
"color": "0075ca",
|
||||
"default": true,
|
||||
"node_id": "LA_kwDOIiC6Ac8AAAABIZgp3g",
|
||||
"description": "Improvements or additions to documentation"
|
||||
},
|
||||
{
|
||||
"id": 5009913913,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev/labels/critical",
|
||||
"name": "critical",
|
||||
"color": "e99695",
|
||||
"default": false,
|
||||
"node_id": "LA_kwDOIiC6Ac8AAAABKp04OQ",
|
||||
"description": ""
|
||||
}
|
||||
],
|
||||
"locked": false,
|
||||
"number": 2,
|
||||
"node_id": "I_kwDOIiC6Ac5aSLQw",
|
||||
"assignee": {
|
||||
"id": 10635986,
|
||||
"url": "https://api.github.com/users/matt-aitken",
|
||||
"type": "User",
|
||||
"login": "matt-aitken",
|
||||
"node_id": "MDQ6VXNlcjEwNjM1OTg2",
|
||||
"html_url": "https://github.com/matt-aitken",
|
||||
"gists_url": "https://api.github.com/users/matt-aitken/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/matt-aitken/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10635986?v=4",
|
||||
"events_url": "https://api.github.com/users/matt-aitken/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/matt-aitken/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/matt-aitken/followers",
|
||||
"following_url": "https://api.github.com/users/matt-aitken/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/matt-aitken/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/matt-aitken/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/matt-aitken/received_events"
|
||||
},
|
||||
"comments": 2,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev/issues/2",
|
||||
"assignees": [
|
||||
{
|
||||
"id": 10635986,
|
||||
"url": "https://api.github.com/users/matt-aitken",
|
||||
"type": "User",
|
||||
"login": "matt-aitken",
|
||||
"node_id": "MDQ6VXNlcjEwNjM1OTg2",
|
||||
"html_url": "https://github.com/matt-aitken",
|
||||
"gists_url": "https://api.github.com/users/matt-aitken/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/matt-aitken/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10635986?v=4",
|
||||
"events_url": "https://api.github.com/users/matt-aitken/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/matt-aitken/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/matt-aitken/followers",
|
||||
"following_url": "https://api.github.com/users/matt-aitken/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/matt-aitken/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/matt-aitken/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/matt-aitken/received_events"
|
||||
}
|
||||
],
|
||||
"closed_at": null,
|
||||
"milestone": null,
|
||||
"reactions": {
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/2/reactions",
|
||||
"eyes": 0,
|
||||
"heart": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"rocket": 0,
|
||||
"confused": 0,
|
||||
"total_count": 0
|
||||
},
|
||||
"created_at": "2022-12-30T18:34:01Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/2/events",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/2/labels{/name}",
|
||||
"updated_at": "2023-01-15T20:18:14Z",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/2/comments",
|
||||
"state_reason": null,
|
||||
"timeline_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/2/timeline",
|
||||
"repository_url": "https://api.github.com/repos/triggerdotdev/trigger.dev",
|
||||
"active_lock_reason": null,
|
||||
"author_association": "MEMBER",
|
||||
"performed_via_github_app": null
|
||||
},
|
||||
"label": {
|
||||
"id": 5009913913,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev/labels/critical",
|
||||
"name": "critical",
|
||||
"color": "e99695",
|
||||
"default": false,
|
||||
"node_id": "LA_kwDOIiC6Ac8AAAABKp04OQ",
|
||||
"description": ""
|
||||
},
|
||||
"action": "labeled",
|
||||
"sender": {
|
||||
"id": 7555566,
|
||||
"url": "https://api.github.com/users/samejr",
|
||||
"type": "User",
|
||||
"login": "samejr",
|
||||
"node_id": "MDQ6VXNlcjc1NTU1NjY=",
|
||||
"html_url": "https://github.com/samejr",
|
||||
"gists_url": "https://api.github.com/users/samejr/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/samejr/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7555566?v=4",
|
||||
"events_url": "https://api.github.com/users/samejr/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/samejr/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/samejr/followers",
|
||||
"following_url": "https://api.github.com/users/samejr/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/samejr/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/samejr/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/samejr/received_events"
|
||||
},
|
||||
"repository": {
|
||||
"id": 572570113,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev",
|
||||
"fork": false,
|
||||
"name": "trigger.dev",
|
||||
"size": 14727,
|
||||
"forks": 2,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [
|
||||
"apis",
|
||||
"automation",
|
||||
"event-driven",
|
||||
"events",
|
||||
"orchestration",
|
||||
"scheduler",
|
||||
"workflows"
|
||||
],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev.git",
|
||||
"license": {
|
||||
"key": "apache-2.0",
|
||||
"url": "https://api.github.com/licenses/apache-2.0",
|
||||
"name": "Apache License 2.0",
|
||||
"node_id": "MDc6TGljZW5zZTI=",
|
||||
"spdx_id": "Apache-2.0"
|
||||
},
|
||||
"node_id": "R_kgDOIiC6AQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": true,
|
||||
"homepage": "https://trigger.dev",
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/tags",
|
||||
"watchers": 58,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/pulls{/number}",
|
||||
"pushed_at": "2023-01-15T19:41:24Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/git/trees{/sha}",
|
||||
"created_at": "2022-11-30T14:59:07Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-15T18:49:01Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/compare/{base}...{head}",
|
||||
"description": "The developer-first, open source Zapier Alternative. Coming soon. Give us a ⭐️ and we'll let you know",
|
||||
"forks_count": 2,
|
||||
"is_template": false,
|
||||
"open_issues": 2,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/downloads",
|
||||
"has_downloads": true,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/stargazers",
|
||||
"watchers_count": 58,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/subscribers",
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/events{/number}",
|
||||
"stargazers_count": 58,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev/notifications{?since,all,participating}",
|
||||
"open_issues_count": 2,
|
||||
"web_commit_signoff_required": false
|
||||
},
|
||||
"organization": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/orgs/triggerdotdev",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"hooks_url": "https://api.github.com/orgs/triggerdotdev/hooks",
|
||||
"repos_url": "https://api.github.com/orgs/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/orgs/triggerdotdev/events",
|
||||
"issues_url": "https://api.github.com/orgs/triggerdotdev/issues",
|
||||
"description": "",
|
||||
"members_url": "https://api.github.com/orgs/triggerdotdev/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/triggerdotdev/public_members{/member}"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,220 +0,0 @@
|
||||
---
|
||||
title: "New Star Event"
|
||||
sidebarTitle: "New Star"
|
||||
description: "Trigger a workflow whenever a user star's the specified GitHub repository."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.newStarEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="repo" type="string" required={true}>
|
||||
The full path to the repository, including the organization
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="action" type="string" default="created">
|
||||
The star action, which in this case is always `"created"`.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="starred_at" type="Date" required={true}>
|
||||
The date and time the starring occurred.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="repository" type="object" required={true}>
|
||||
A repository on GitHub.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="sender" type="object" required={true}>
|
||||
The GitHub user object who starred the repository.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="organization" type="object">
|
||||
The organization object the repository belongs to.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on New GitHub Star
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
id: "new-star",
|
||||
name: "On New Star",
|
||||
on: github.events.newStarEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await slack.postMessage("⭐️ New Star", {
|
||||
channelName: "github-stars",
|
||||
text: `Repo ${event.repository.full_name} got a star from ${event.sender.login}, for a total of ${event.repository.stargazers_count} stars!`,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Event payload
|
||||
|
||||
```json Example
|
||||
{
|
||||
"action": "created",
|
||||
"starred_at": "2023-01-21T23:47:38Z",
|
||||
"repository": {
|
||||
"id": 516315865,
|
||||
"node_id": "R_kgDOHsZa2Q",
|
||||
"name": "apihero-openapi-generator",
|
||||
"full_name": "triggerdotdev/apihero-openapi-generator",
|
||||
"private": false,
|
||||
"owner": {
|
||||
"login": "triggerdotdev",
|
||||
"id": 95297378,
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events",
|
||||
"type": "Organization",
|
||||
"site_admin": false
|
||||
},
|
||||
"html_url": "https://github.com/triggerdotdev/apihero-openapi-generator",
|
||||
"description": null,
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/forks",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/teams",
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/events",
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/tags",
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/subscription",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/merges",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/downloads",
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/releases{/id}",
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/apihero-openapi-generator/deployments",
|
||||
"created_at": "2022-07-21T09:57:53Z",
|
||||
"updated_at": "2023-01-21T23:47:38Z",
|
||||
"pushed_at": "2022-10-20T13:21:09Z",
|
||||
"git_url": "git://github.com/triggerdotdev/apihero-openapi-generator.git",
|
||||
"ssh_url": "git@github.com:triggerdotdev/apihero-openapi-generator.git",
|
||||
"clone_url": "https://github.com/triggerdotdev/apihero-openapi-generator.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/apihero-openapi-generator",
|
||||
"homepage": null,
|
||||
"size": 4962,
|
||||
"stargazers_count": 1,
|
||||
"watchers_count": 1,
|
||||
"language": "TypeScript",
|
||||
"has_issues": true,
|
||||
"has_projects": true,
|
||||
"has_downloads": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_discussions": false,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"open_issues_count": 0,
|
||||
"license": {
|
||||
"key": "mit",
|
||||
"name": "MIT License",
|
||||
"spdx_id": "MIT",
|
||||
"url": "https://api.github.com/licenses/mit",
|
||||
"node_id": "MDc6TGljZW5zZTEz"
|
||||
},
|
||||
"allow_forking": true,
|
||||
"is_template": false,
|
||||
"web_commit_signoff_required": false,
|
||||
"topics": [],
|
||||
"visibility": "public",
|
||||
"forks": 0,
|
||||
"open_issues": 0,
|
||||
"watchers": 1,
|
||||
"default_branch": "main"
|
||||
},
|
||||
"organization": {
|
||||
"login": "triggerdotdev",
|
||||
"id": 95297378,
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"url": "https://api.github.com/orgs/triggerdotdev",
|
||||
"repos_url": "https://api.github.com/orgs/triggerdotdev/repos",
|
||||
"events_url": "https://api.github.com/orgs/triggerdotdev/events",
|
||||
"hooks_url": "https://api.github.com/orgs/triggerdotdev/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/triggerdotdev/issues",
|
||||
"members_url": "https://api.github.com/orgs/triggerdotdev/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/triggerdotdev/public_members{/member}",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"description": ""
|
||||
},
|
||||
"sender": {
|
||||
"login": "ericallam",
|
||||
"id": 534,
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,97 +0,0 @@
|
||||
---
|
||||
title: "PR Review Comment Event"
|
||||
sidebarTitle: "PR Review Comments"
|
||||
description: "Trigger a workflow whenever an pull_request_review_comment action is performed in a GitHub repository."
|
||||
---
|
||||
|
||||
<Note>
|
||||
If you would like to trigger a workflow when a comment is made on a PR, use
|
||||
the [issueCommentEvent](/integrations/apis/github/events/issue-comments)
|
||||
instead
|
||||
</Note>
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.pullRequestCommentEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="repo" type="string" required={true}>
|
||||
The full path to the repository, including the organization
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="action" type="string">
|
||||
The pull_request action, can be one of: `created`, `edited`, `deleted`.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="comment" type="object" required={true}>
|
||||
The pull request review comment object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="pull_request" type="object" required={true}>
|
||||
The pull request object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="repository" type="object" required={true}>
|
||||
A repository on GitHub.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="sender" type="object" required={true}>
|
||||
The GitHub user object who performed the action.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="organization" type="object">
|
||||
The organization object the repository belongs to.
|
||||
</ResponseField>
|
||||
|
||||
## Additional event fields
|
||||
|
||||
### edited PR Review Comment
|
||||
|
||||
<ResponseField name="changes" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="body" type="object">
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ResponseField name="from" type="string">
|
||||
The previous body text.
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on new PR
|
||||
new Trigger({
|
||||
id: "new-pr",
|
||||
name: "Notify Slack on new PR Review Comment",
|
||||
on: github.events.pullRequestCommentEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (event.action === "created") {
|
||||
await slack.postMessage("New PR comment", {
|
||||
channelName: "github-prs",
|
||||
text: `New PR comment by ${event.sender.login} on PR ${event.pull_request.title} (${event.pull_request.html_url})`,
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,625 +0,0 @@
|
||||
---
|
||||
title: "PR Review Event"
|
||||
sidebarTitle: "PR Reviews"
|
||||
description: "Trigger a workflow whenever an pull_request_review action is performed in a GitHub repository."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.pullRequestReviewEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="repo" type="string" required={true}>
|
||||
The full path to the repository, including the organization
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="action" type="string">
|
||||
The pull_request_review action, can be one of: `submitted`, `edited`,
|
||||
`dismissed`.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="review" type="object" required={true}>
|
||||
The pull request review object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="pull_request" type="object" required={true}>
|
||||
The pull request object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="repository" type="object" required={true}>
|
||||
A repository on GitHub.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="sender" type="object" required={true}>
|
||||
The GitHub user object who performed the action.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="organization" type="object">
|
||||
The organization object the repository belongs to.
|
||||
</ResponseField>
|
||||
|
||||
## Additional event fields
|
||||
|
||||
### edited PR Review
|
||||
|
||||
<ResponseField name="changes" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="body" type="object">
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ResponseField name="from" type="string">
|
||||
The previous body text.
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on new PR Review
|
||||
new Trigger({
|
||||
id: "new-pr",
|
||||
name: "Notify Slack on new PR Review",
|
||||
on: github.events.pullRequestReviewEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (event.action === "submitted") {
|
||||
await slack.postMessage("New PR Review", {
|
||||
channelName: "github-prs",
|
||||
text: `New PR Review by ${event.sender.login} on PR ${event.pull_request.title} (${event.pull_request.html_url})`,
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Event payload
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "submitted",
|
||||
"review": {
|
||||
"id": 1266763458,
|
||||
"body": "This is a PR review comment?",
|
||||
"user": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"state": "commented",
|
||||
"_links": {
|
||||
"html": {
|
||||
"href": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4#pullrequestreview-1266763458"
|
||||
},
|
||||
"pull_request": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4"
|
||||
}
|
||||
},
|
||||
"node_id": "PRR_kwDOIxVdCc5LgUbC",
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4#pullrequestreview-1266763458",
|
||||
"commit_id": "efc58e149c06f4a45ebf7a0bf34ac25cdcd34b07",
|
||||
"submitted_at": "2023-01-24T04:24:58Z",
|
||||
"pull_request_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4",
|
||||
"author_association": "MEMBER"
|
||||
},
|
||||
"sender": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"repository": {
|
||||
"id": 588602633,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": "2023-01-24T04:20:52Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": "2023-01-13T14:26:45Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 3,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 3,
|
||||
"web_commit_signoff_required": false
|
||||
},
|
||||
"organization": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/orgs/triggerdotdev",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"hooks_url": "https://api.github.com/orgs/triggerdotdev/hooks",
|
||||
"repos_url": "https://api.github.com/orgs/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/orgs/triggerdotdev/events",
|
||||
"issues_url": "https://api.github.com/orgs/triggerdotdev/issues",
|
||||
"description": "",
|
||||
"members_url": "https://api.github.com/orgs/triggerdotdev/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/triggerdotdev/public_members{/member}"
|
||||
},
|
||||
"pull_request": {
|
||||
"id": 1214500311,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4",
|
||||
"base": {
|
||||
"ref": "main",
|
||||
"sha": "e7c0680e23fcd3e52d35ddfbb4076112c640d9fa",
|
||||
"repo": {
|
||||
"id": 588602633,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": "2023-01-24T04:20:52Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": "2023-01-13T14:26:45Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 3,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"allow_auto_merge": false,
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 3,
|
||||
"allow_merge_commit": true,
|
||||
"allow_rebase_merge": true,
|
||||
"allow_squash_merge": true,
|
||||
"merge_commit_title": "MERGE_MESSAGE",
|
||||
"allow_update_branch": false,
|
||||
"merge_commit_message": "PR_TITLE",
|
||||
"delete_branch_on_merge": false,
|
||||
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
|
||||
"squash_merge_commit_message": "COMMIT_MESSAGES",
|
||||
"web_commit_signoff_required": false,
|
||||
"use_squash_pr_title_as_default": false
|
||||
},
|
||||
"user": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"label": "triggerdotdev:main"
|
||||
},
|
||||
"body": null,
|
||||
"head": {
|
||||
"ref": "resend",
|
||||
"sha": "efc58e149c06f4a45ebf7a0bf34ac25cdcd34b07",
|
||||
"repo": {
|
||||
"id": 588602633,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": "2023-01-24T04:20:52Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": "2023-01-13T14:26:45Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 3,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"allow_auto_merge": false,
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 3,
|
||||
"allow_merge_commit": true,
|
||||
"allow_rebase_merge": true,
|
||||
"allow_squash_merge": true,
|
||||
"merge_commit_title": "MERGE_MESSAGE",
|
||||
"allow_update_branch": false,
|
||||
"merge_commit_message": "PR_TITLE",
|
||||
"delete_branch_on_merge": false,
|
||||
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
|
||||
"squash_merge_commit_message": "COMMIT_MESSAGES",
|
||||
"web_commit_signoff_required": false,
|
||||
"use_squash_pr_title_as_default": false
|
||||
},
|
||||
"user": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"label": "triggerdotdev:resend"
|
||||
},
|
||||
"user": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"draft": false,
|
||||
"state": "open",
|
||||
"title": "Example PR",
|
||||
"_links": {
|
||||
"html": {
|
||||
"href": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4"
|
||||
},
|
||||
"self": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4"
|
||||
},
|
||||
"issue": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4"
|
||||
},
|
||||
"commits": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/commits"
|
||||
},
|
||||
"comments": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4/comments"
|
||||
},
|
||||
"statuses": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/efc58e149c06f4a45ebf7a0bf34ac25cdcd34b07"
|
||||
},
|
||||
"review_comment": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/comments{/number}"
|
||||
},
|
||||
"review_comments": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/comments"
|
||||
}
|
||||
},
|
||||
"labels": [],
|
||||
"locked": false,
|
||||
"number": 4,
|
||||
"node_id": "PR_kwDOIxVdCc5IY83X",
|
||||
"assignee": null,
|
||||
"diff_url": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4.diff",
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4",
|
||||
"assignees": [],
|
||||
"closed_at": null,
|
||||
"issue_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4",
|
||||
"merged_at": null,
|
||||
"milestone": null,
|
||||
"patch_url": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4.patch",
|
||||
"auto_merge": null,
|
||||
"created_at": "2023-01-24T04:20:51Z",
|
||||
"updated_at": "2023-01-24T04:24:58Z",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/commits",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4/comments",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/efc58e149c06f4a45ebf7a0bf34ac25cdcd34b07",
|
||||
"requested_teams": [],
|
||||
"merge_commit_sha": null,
|
||||
"active_lock_reason": null,
|
||||
"author_association": "MEMBER",
|
||||
"review_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/comments{/number}",
|
||||
"requested_reviewers": [],
|
||||
"review_comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/comments"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,644 +0,0 @@
|
||||
---
|
||||
title: "Pull Request Event"
|
||||
sidebarTitle: "Pull Requests"
|
||||
description: "Trigger a workflow whenever an pull_request action is performed in a GitHub repository."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.pullRequestEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="repo" type="string" required={true}>
|
||||
The full path to the repository, including the organization
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="action" type="string">
|
||||
The pull_request action, which can one of assigned, unassigned,
|
||||
auto_merge_enabled, auto_merge_disabled, review_requested,
|
||||
review_request_removed, ready_for_review, labeled, unlabeled, opened, edited,
|
||||
closed, reopened, synchronize, ready_for_review, locked, unlocked, or
|
||||
converted_to_draft.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="number" type="number" required={true}>
|
||||
The pull request number.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="pull_request" type="object" required={true}>
|
||||
The pull request object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="repository" type="object" required={true}>
|
||||
A repository on GitHub.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="sender" type="object" required={true}>
|
||||
The GitHub user object who performed the action.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="organization" type="object">
|
||||
The organization object the repository belongs to.
|
||||
</ResponseField>
|
||||
|
||||
## Additional event fields
|
||||
|
||||
### review_requested/review_request_removed PRs
|
||||
|
||||
<ResponseField name="requested_reviewer" type="object">
|
||||
The GitHub user object who was requested to review the PR.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="requested_team" type="object">
|
||||
The GitHub team object who was requested to review the PR.
|
||||
</ResponseField>
|
||||
|
||||
### labeled/unlabeled PRs
|
||||
|
||||
<ResponseField name="label" type="object">
|
||||
The label object.
|
||||
</ResponseField>
|
||||
|
||||
### assigned/unassigned PRs
|
||||
|
||||
<ResponseField name="assignee" type="object">
|
||||
The assignee object.
|
||||
</ResponseField>
|
||||
|
||||
### edited PRs
|
||||
|
||||
<ResponseField name="changes" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="body" type="object">
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ResponseField name="from" type="string">
|
||||
The previous body text.
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="title" type="object">
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ResponseField name="from" type="string">
|
||||
The previous title text.
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="base" type="object">
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ResponseField name="ref" type="object">
|
||||
Use `ref.from` to get the previous base branch name.
|
||||
</ResponseField>
|
||||
<ResponseField name="sha" type="object">
|
||||
Use `sha.from` to get the previous base branch SHA.
|
||||
</ResponseField>
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on new PR
|
||||
new Trigger({
|
||||
id: "new-pr",
|
||||
name: "Notify Slack on new PR",
|
||||
on: github.events.pullRequestEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (event.action === "opened") {
|
||||
await slack.postMessage("New PR", {
|
||||
channelName: "github-prs",
|
||||
text: `New PR: ${event.pull_request.html_url}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Event payload
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "opened",
|
||||
"number": 4,
|
||||
"sender": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"repository": {
|
||||
"id": 588602633,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": "2023-01-24T04:20:52Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": "2023-01-13T14:26:45Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 3,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 3,
|
||||
"web_commit_signoff_required": false
|
||||
},
|
||||
"organization": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/orgs/triggerdotdev",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"hooks_url": "https://api.github.com/orgs/triggerdotdev/hooks",
|
||||
"repos_url": "https://api.github.com/orgs/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/orgs/triggerdotdev/events",
|
||||
"issues_url": "https://api.github.com/orgs/triggerdotdev/issues",
|
||||
"description": "",
|
||||
"members_url": "https://api.github.com/orgs/triggerdotdev/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/triggerdotdev/public_members{/member}"
|
||||
},
|
||||
"pull_request": {
|
||||
"id": 1214500311,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4",
|
||||
"base": {
|
||||
"ref": "main",
|
||||
"sha": "e7c0680e23fcd3e52d35ddfbb4076112c640d9fa",
|
||||
"repo": {
|
||||
"id": 588602633,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": "2023-01-24T04:20:52Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": "2023-01-13T14:26:45Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 3,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"allow_auto_merge": false,
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 3,
|
||||
"allow_merge_commit": true,
|
||||
"allow_rebase_merge": true,
|
||||
"allow_squash_merge": true,
|
||||
"merge_commit_title": "MERGE_MESSAGE",
|
||||
"allow_update_branch": false,
|
||||
"merge_commit_message": "PR_TITLE",
|
||||
"delete_branch_on_merge": false,
|
||||
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
|
||||
"squash_merge_commit_message": "COMMIT_MESSAGES",
|
||||
"web_commit_signoff_required": false,
|
||||
"use_squash_pr_title_as_default": false
|
||||
},
|
||||
"user": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"label": "triggerdotdev:main"
|
||||
},
|
||||
"body": null,
|
||||
"head": {
|
||||
"ref": "resend",
|
||||
"sha": "efc58e149c06f4a45ebf7a0bf34ac25cdcd34b07",
|
||||
"repo": {
|
||||
"id": 588602633,
|
||||
"url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": "2023-01-24T04:20:52Z",
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": "2023-01-13T14:26:45Z",
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 3,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"allow_auto_merge": false,
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 3,
|
||||
"allow_merge_commit": true,
|
||||
"allow_rebase_merge": true,
|
||||
"allow_squash_merge": true,
|
||||
"merge_commit_title": "MERGE_MESSAGE",
|
||||
"allow_update_branch": false,
|
||||
"merge_commit_message": "PR_TITLE",
|
||||
"delete_branch_on_merge": false,
|
||||
"squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
|
||||
"squash_merge_commit_message": "COMMIT_MESSAGES",
|
||||
"web_commit_signoff_required": false,
|
||||
"use_squash_pr_title_as_default": false
|
||||
},
|
||||
"user": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"type": "Organization",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"label": "triggerdotdev:resend"
|
||||
},
|
||||
"user": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"draft": false,
|
||||
"state": "open",
|
||||
"title": "Example PR",
|
||||
"_links": {
|
||||
"html": {
|
||||
"href": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4"
|
||||
},
|
||||
"self": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4"
|
||||
},
|
||||
"issue": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4"
|
||||
},
|
||||
"commits": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/commits"
|
||||
},
|
||||
"comments": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4/comments"
|
||||
},
|
||||
"statuses": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/efc58e149c06f4a45ebf7a0bf34ac25cdcd34b07"
|
||||
},
|
||||
"review_comment": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/comments{/number}"
|
||||
},
|
||||
"review_comments": {
|
||||
"href": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/comments"
|
||||
}
|
||||
},
|
||||
"labels": [],
|
||||
"locked": false,
|
||||
"merged": false,
|
||||
"number": 4,
|
||||
"commits": 1,
|
||||
"node_id": "PR_kwDOIxVdCc5IY83X",
|
||||
"assignee": null,
|
||||
"comments": 0,
|
||||
"diff_url": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4.diff",
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4",
|
||||
"additions": 220,
|
||||
"assignees": [],
|
||||
"closed_at": null,
|
||||
"deletions": 0,
|
||||
"issue_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4",
|
||||
"mergeable": null,
|
||||
"merged_at": null,
|
||||
"merged_by": null,
|
||||
"milestone": null,
|
||||
"patch_url": "https://github.com/triggerdotdev/trigger.dev-examples/pull/4.patch",
|
||||
"auto_merge": null,
|
||||
"created_at": "2023-01-24T04:20:51Z",
|
||||
"rebaseable": null,
|
||||
"updated_at": "2023-01-24T04:20:51Z",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/commits",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/4/comments",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/efc58e149c06f4a45ebf7a0bf34ac25cdcd34b07",
|
||||
"changed_files": 3,
|
||||
"mergeable_state": "unknown",
|
||||
"requested_teams": [],
|
||||
"review_comments": 0,
|
||||
"merge_commit_sha": null,
|
||||
"active_lock_reason": null,
|
||||
"author_association": "MEMBER",
|
||||
"review_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/comments{/number}",
|
||||
"requested_reviewers": [],
|
||||
"review_comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls/4/comments",
|
||||
"maintainer_can_modify": false
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,311 +0,0 @@
|
||||
---
|
||||
title: "Push Event"
|
||||
sidebarTitle: "Pushes"
|
||||
description: "Trigger a workflow whenever a push action is performed in a GitHub repository."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.pushEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="repo" type="string" required={true}>
|
||||
The full path to the repository, including the organization
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="ref" type="string">
|
||||
The full git ref that was pushed. Example: refs/heads/master.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="before" type="string">
|
||||
The SHA of the commit before the push.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="after" type="string">
|
||||
The SHA of the commit after the push.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="created" type="boolean">
|
||||
Whether this was a created branch or tag.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="deleted" type="boolean">
|
||||
Whether this was a deleted branch or tag.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="forced" type="boolean">
|
||||
Whether this was a forced update or not.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="base_ref" type="string">
|
||||
If the ref is a branch, this is the branch name that the push was made to.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="compare" type="string">
|
||||
The HTTP URL to compare the two commits.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="commits" type="array">
|
||||
An array of commit objects describing the pushed commits.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="head_commit" type="object">
|
||||
The head commit object.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="repository" type="object" required={true}>
|
||||
A repository on GitHub.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="sender" type="object" required={true}>
|
||||
The GitHub user object who performed the action.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="organization" type="object">
|
||||
The organization object the repository belongs to.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on new push
|
||||
new Trigger({
|
||||
id: "github-to-slack",
|
||||
name: "Notify of new push",
|
||||
on: github.events.pushEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await slack.postMessage("New push to trigger.dev", {
|
||||
channel: "github-changes",
|
||||
text: `New push to trigger.dev by ${event.sender.login}: ${event.compare}`,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Event payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ref": "refs/heads/main",
|
||||
"after": "4a0834a1daa09cdd1a03038dbc131f807d887de8",
|
||||
"before": "e7c0680e23fcd3e52d35ddfbb4076112c640d9fa",
|
||||
"forced": false,
|
||||
"pusher": {
|
||||
"name": "ericallam",
|
||||
"email": "eallam@icloud.com"
|
||||
},
|
||||
"sender": {
|
||||
"id": 534,
|
||||
"url": "https://api.github.com/users/ericallam",
|
||||
"type": "User",
|
||||
"login": "ericallam",
|
||||
"node_id": "MDQ6VXNlcjUzNA==",
|
||||
"html_url": "https://github.com/ericallam",
|
||||
"gists_url": "https://api.github.com/users/ericallam/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/ericallam/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/534?v=4",
|
||||
"events_url": "https://api.github.com/users/ericallam/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/ericallam/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/ericallam/followers",
|
||||
"following_url": "https://api.github.com/users/ericallam/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/ericallam/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/ericallam/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/ericallam/received_events"
|
||||
},
|
||||
"commits": [
|
||||
{
|
||||
"id": "4a0834a1daa09cdd1a03038dbc131f807d887de8",
|
||||
"url": "https://github.com/triggerdotdev/trigger.dev-examples/commit/4a0834a1daa09cdd1a03038dbc131f807d887de8",
|
||||
"added": [],
|
||||
"author": {
|
||||
"name": "Eric Allam",
|
||||
"email": "eallam@icloud.com",
|
||||
"username": "ericallam"
|
||||
},
|
||||
"message": "Add some documentation for how to run (needs work)",
|
||||
"removed": [],
|
||||
"tree_id": "5c06942324e80422eea4f4c11ff80d4bd8f9d7a7",
|
||||
"distinct": true,
|
||||
"modified": [
|
||||
"README.md",
|
||||
"pnpm-lock.yaml",
|
||||
"src/examples/github-webhook.ts"
|
||||
],
|
||||
"committer": {
|
||||
"name": "Eric Allam",
|
||||
"email": "eallam@icloud.com",
|
||||
"username": "ericallam"
|
||||
},
|
||||
"timestamp": "2023-01-24T04:43:40Z"
|
||||
}
|
||||
],
|
||||
"compare": "https://github.com/triggerdotdev/trigger.dev-examples/compare/e7c0680e23fc...4a0834a1daa0",
|
||||
"created": false,
|
||||
"deleted": false,
|
||||
"base_ref": null,
|
||||
"repository": {
|
||||
"id": 588602633,
|
||||
"url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"fork": false,
|
||||
"name": "trigger.dev-examples",
|
||||
"size": 161,
|
||||
"forks": 0,
|
||||
"owner": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/users/triggerdotdev",
|
||||
"name": "triggerdotdev",
|
||||
"type": "Organization",
|
||||
"email": "hello@trigger.dev",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"html_url": "https://github.com/triggerdotdev",
|
||||
"gists_url": "https://api.github.com/users/triggerdotdev/gists{/gist_id}",
|
||||
"repos_url": "https://api.github.com/users/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/users/triggerdotdev/events{/privacy}",
|
||||
"site_admin": false,
|
||||
"gravatar_id": "",
|
||||
"starred_url": "https://api.github.com/users/triggerdotdev/starred{/owner}{/repo}",
|
||||
"followers_url": "https://api.github.com/users/triggerdotdev/followers",
|
||||
"following_url": "https://api.github.com/users/triggerdotdev/following{/other_user}",
|
||||
"organizations_url": "https://api.github.com/users/triggerdotdev/orgs",
|
||||
"subscriptions_url": "https://api.github.com/users/triggerdotdev/subscriptions",
|
||||
"received_events_url": "https://api.github.com/users/triggerdotdev/received_events"
|
||||
},
|
||||
"topics": [],
|
||||
"git_url": "git://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"license": null,
|
||||
"node_id": "R_kgDOIxVdCQ",
|
||||
"private": false,
|
||||
"ssh_url": "git@github.com:triggerdotdev/trigger.dev-examples.git",
|
||||
"svn_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"has_wiki": false,
|
||||
"homepage": null,
|
||||
"html_url": "https://github.com/triggerdotdev/trigger.dev-examples",
|
||||
"keys_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/keys{/key_id}",
|
||||
"language": "TypeScript",
|
||||
"tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/tags",
|
||||
"watchers": 1,
|
||||
"blobs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/blobs{/sha}",
|
||||
"clone_url": "https://github.com/triggerdotdev/trigger.dev-examples.git",
|
||||
"forks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/forks",
|
||||
"full_name": "triggerdotdev/trigger.dev-examples",
|
||||
"has_pages": false,
|
||||
"hooks_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/hooks",
|
||||
"pulls_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/pulls{/number}",
|
||||
"pushed_at": 1674535423,
|
||||
"teams_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/teams",
|
||||
"trees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/trees{/sha}",
|
||||
"created_at": 1673620005,
|
||||
"events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/events",
|
||||
"has_issues": true,
|
||||
"issues_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues{/number}",
|
||||
"labels_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/labels{/name}",
|
||||
"merges_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/merges",
|
||||
"mirror_url": null,
|
||||
"stargazers": 1,
|
||||
"updated_at": "2023-01-23T14:22:40Z",
|
||||
"visibility": "public",
|
||||
"archive_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/{archive_format}{/ref}",
|
||||
"commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/compare/{base}...{head}",
|
||||
"description": "Node.js project with multiple example Trigger.dev workflows",
|
||||
"forks_count": 0,
|
||||
"is_template": false,
|
||||
"open_issues": 2,
|
||||
"branches_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/branches{/branch}",
|
||||
"comments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contents/{+path}",
|
||||
"git_refs_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/tags{/sha}",
|
||||
"has_projects": true,
|
||||
"organization": "triggerdotdev",
|
||||
"releases_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/releases{/id}",
|
||||
"statuses_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/statuses/{sha}",
|
||||
"allow_forking": true,
|
||||
"assignees_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/assignees{/user}",
|
||||
"downloads_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/downloads",
|
||||
"has_downloads": false,
|
||||
"languages_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/languages",
|
||||
"master_branch": "main",
|
||||
"default_branch": "main",
|
||||
"milestones_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/milestones{/number}",
|
||||
"stargazers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/stargazers",
|
||||
"watchers_count": 1,
|
||||
"deployments_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/deployments",
|
||||
"git_commits_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/git/commits{/sha}",
|
||||
"has_discussions": false,
|
||||
"subscribers_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscribers",
|
||||
"contributors_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/contributors",
|
||||
"issue_events_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/events{/number}",
|
||||
"stargazers_count": 1,
|
||||
"subscription_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/subscription",
|
||||
"collaborators_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/collaborators{/collaborator}",
|
||||
"issue_comment_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/issues/comments{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/triggerdotdev/trigger.dev-examples/notifications{?since,all,participating}",
|
||||
"open_issues_count": 2,
|
||||
"web_commit_signoff_required": false
|
||||
},
|
||||
"head_commit": {
|
||||
"id": "4a0834a1daa09cdd1a03038dbc131f807d887de8",
|
||||
"url": "https://github.com/triggerdotdev/trigger.dev-examples/commit/4a0834a1daa09cdd1a03038dbc131f807d887de8",
|
||||
"added": [],
|
||||
"author": {
|
||||
"name": "Eric Allam",
|
||||
"email": "eallam@icloud.com",
|
||||
"username": "ericallam"
|
||||
},
|
||||
"message": "Add some documentation for how to run (needs work)",
|
||||
"removed": [],
|
||||
"tree_id": "5c06942324e80422eea4f4c11ff80d4bd8f9d7a7",
|
||||
"distinct": true,
|
||||
"modified": [
|
||||
"README.md",
|
||||
"pnpm-lock.yaml",
|
||||
"src/examples/github-webhook.ts"
|
||||
],
|
||||
"committer": {
|
||||
"name": "Eric Allam",
|
||||
"email": "eallam@icloud.com",
|
||||
"username": "ericallam"
|
||||
},
|
||||
"timestamp": "2023-01-24T04:43:40Z"
|
||||
},
|
||||
"organization": {
|
||||
"id": 95297378,
|
||||
"url": "https://api.github.com/orgs/triggerdotdev",
|
||||
"login": "triggerdotdev",
|
||||
"node_id": "O_kgDOBa4fYg",
|
||||
"hooks_url": "https://api.github.com/orgs/triggerdotdev/hooks",
|
||||
"repos_url": "https://api.github.com/orgs/triggerdotdev/repos",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95297378?v=4",
|
||||
"events_url": "https://api.github.com/orgs/triggerdotdev/events",
|
||||
"issues_url": "https://api.github.com/orgs/triggerdotdev/issues",
|
||||
"description": "",
|
||||
"members_url": "https://api.github.com/orgs/triggerdotdev/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/triggerdotdev/public_members{/member}"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,132 +0,0 @@
|
||||
---
|
||||
title: "Send Email"
|
||||
sidebarTitle: "Send Email"
|
||||
description: "Send email using Resend.com"
|
||||
---
|
||||
|
||||
<Tip>
|
||||
Resend.com is currently in private beta but you can request early access
|
||||
[here](https://resend.com/).
|
||||
</Tip>
|
||||
|
||||
|
||||
<Note>
|
||||
If you'd like to render emails using React, please see the [React.email
|
||||
docs](https://react.email/)
|
||||
</Note>
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="text" type="string" required={false}>
|
||||
The text of the email. If `html` is provided, this will be used as the
|
||||
plain text version of the email.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="html" type="string" required={false}>
|
||||
The HTML of the email. If `text` is provided, this will be used as the
|
||||
HTML version of the email.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="react" type="react component" required={false}>
|
||||
A React component that will be rendered to HTML and used as the email
|
||||
content. Please see the [React.email docs](https://react.email/) for more info
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="subject" type="string" required={true}>
|
||||
The subject of the email.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="from" type="string" required={true}>
|
||||
The email address of the sender.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string | string[]" required={true}>
|
||||
One or more email addresses of the recipients.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="cc" type="string | string[]" required={false}>
|
||||
One or more email addresses of the CC recipients.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="bcc" type="string | string[]" required={false}>
|
||||
One or more email addresses of the BCC recipients.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="replyTo" type="string | string[]" required={false}>
|
||||
An optional email address to use as the reply-to address.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="id" type="string">
|
||||
The ID of the email.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="from" type="string">
|
||||
The email address of the sender.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="to" type="string">
|
||||
The email address of the recipient.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="created_at" type="string">
|
||||
The date and time the email was created.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript criticalIssue.tsx
|
||||
import * as github from "@trigger.dev/github";
|
||||
import * as resend from "@trigger.dev/resend";
|
||||
import { CriticalIssueEmail } from "./emails";
|
||||
|
||||
new Trigger({
|
||||
id: "email-ops",
|
||||
name: "On Critical Issue",
|
||||
on: github.events.issueEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (event.action === "labeled" && event.label.name === "critical") {
|
||||
await resend.sendEmail("🚨 Alert Ops", {
|
||||
to: "ops@trigger.dev",
|
||||
from: "internal@trigger.dev",
|
||||
subject: `Critical issue: ${event.issue.title}`,
|
||||
react: (
|
||||
<CriticalIssueEmail
|
||||
issue={event.issue}
|
||||
sender={event.sender}
|
||||
repo={event.repository}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Response
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "1673618429",
|
||||
"from": "internal@trigger.dev",
|
||||
"to": "ops@trigger.dev",
|
||||
"created_at": "2023-01-24T14:38:26Z"
|
||||
}
|
||||
```
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
title: "Shopify"
|
||||
sidebarTitle: "Shopify"
|
||||
description: "Support for the Shopify API"
|
||||
---
|
||||
|
||||
## Shopify API integration
|
||||
|
||||
Full reference of all functions is coming soon.
|
||||
|
||||
Check out some example workflows using the Shopify API [here](/examples/shopify).
|
||||
@@ -1,11 +0,0 @@
|
||||
---
|
||||
title: "Slack"
|
||||
sidebarTitle: "Slack"
|
||||
description: "Support for the Slack API"
|
||||
---
|
||||
|
||||
## Slack API integration
|
||||
|
||||
Full reference of all functions is coming soon.
|
||||
|
||||
Check out some example workflows using the Slack API [here](/examples/slack).
|
||||
@@ -1,69 +0,0 @@
|
||||
---
|
||||
title: "Add Reaction"
|
||||
sidebarTitle: "Add Reaction"
|
||||
description: "Add a reaction to a message in Slack."
|
||||
---
|
||||
|
||||
Adds an emoji reaction to a message in Slack. Useful when using the [blockActionInteraction](../events/block-action-interaction) event.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="options" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="name" type="string" required={true}>
|
||||
The name of the emoji to add as a reaction (without colons). (Check out [this emoji cheatsheet](https://www.webfx.com/tools/emoji-cheat-sheet/) to see what's available.)
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="timestamp" type="string" required={true}>
|
||||
The timestamp of the message to add the reaction to. E.g. `1631234567.123456`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="channelName" type="string" required={false}>
|
||||
The name of the channel, can optionally include the `#`. E.g. `#team`.
|
||||
Alternatively you can use the `channelId` param.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="channelId" type="string" required={false}>
|
||||
The slack ID of the channel, e.g. `C04GWUTDC4W`. Can be used instead of `channelName`. Use `channelId` if the slack channel name could change.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="ok" type="boolean" default="true">
|
||||
Always true; non-ok responses will halt the workflow run and throw an error.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts triggers.ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
id: "slack-block-interaction",
|
||||
name: "Slack Block Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "issue.action.block",
|
||||
actionId: ["status-blocked", "status-help", "rating"],
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
return slack.addReaction("Adding a funny reaction to the message", {
|
||||
name: "laughing",
|
||||
timestamp: event.message.ts,
|
||||
channelId: event.channel.id,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,634 +0,0 @@
|
||||
---
|
||||
title: "Open View"
|
||||
sidebarTitle: "Open View"
|
||||
description: "Open a view for a user, usually in response to a user action."
|
||||
---
|
||||
|
||||
Open a modal view for a user after a button click or other user action. The view is a modal that blocks other user interactions with your app, and can be used to collect more complex input from users.
|
||||
|
||||
To be able to open a view, you must first acquire a `trigger_id` from a user interaction, such as a button click. See the [blockActionInteraction docs](../events/block-action-interaction) for more info on triggering on user actions.
|
||||
|
||||
<Note>
|
||||
`trigger_id`'s are valid for only 3 seconds, so make sure not to add any
|
||||
delays before calling `openView`
|
||||
</Note>
|
||||
|
||||
## Usage
|
||||
|
||||
There are 3 steps to opening a view:
|
||||
|
||||
1. Post a message to a channel with an interactive component (button, select menu, etc).
|
||||
2. Listen for a user interaction with that component (using [blockActionInteraction](../events/block-action-interaction)).
|
||||
3. Call `openView` with the `trigger_id` from the interaction.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts step1.ts
|
||||
// This is inside a Trigger.run handler, but extracted for brevity
|
||||
await slack.postMessage("New Issue", {
|
||||
channelName: "github-issues",
|
||||
text: "There is a new GitHub issue in the repo",
|
||||
metadata: { githubIssueId },
|
||||
blocks: [
|
||||
{
|
||||
type: "actions",
|
||||
block_id: "new.issue", // this is the block_id that we'll use to identify the message
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
action_id: "reply",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "Reply to Issue",
|
||||
},
|
||||
value: "reply",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
```ts step2.ts
|
||||
new Trigger({
|
||||
id: "github-issue-slack-interaction",
|
||||
name: "GitHub Issue Slack Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "new.issue",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
// Use the trigger_id from the event to open the view
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```ts step3.ts
|
||||
new Trigger({
|
||||
id: "github-issue-slack-interaction",
|
||||
name: "GitHub Issue Slack Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "new.issue",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await slack.openView("Get the reply", event.trigger_id, {
|
||||
type: "modal",
|
||||
callback_id: "reply",
|
||||
title: {
|
||||
type: "plain_text",
|
||||
text: "Reply to Issue",
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
type: "input",
|
||||
block_id: "replyInput",
|
||||
element: {
|
||||
type: "plain_text_input",
|
||||
action_id: "reply",
|
||||
},
|
||||
label: {
|
||||
type: "plain_text",
|
||||
text: "Reply",
|
||||
},
|
||||
},
|
||||
],
|
||||
submit: {
|
||||
type: "plain_text",
|
||||
text: "Submit",
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Modal Validation
|
||||
|
||||
You can optional provide a validation schema (using [Zod](/guides/zod)) which we will use to validate the view submission and provide feedback to the user.
|
||||
|
||||
For example, we could make sure the `replyInput` above is more than 3 characters and less than 500 characters:
|
||||
|
||||
```ts
|
||||
await slack.openView(
|
||||
"Get the reply",
|
||||
event.trigger_id,
|
||||
{
|
||||
type: "modal",
|
||||
callback_id: "reply",
|
||||
title: {
|
||||
type: "plain_text",
|
||||
text: "Reply to Issue",
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
type: "input",
|
||||
block_id: "replyInput",
|
||||
element: {
|
||||
type: "plain_text_input",
|
||||
action_id: "reply",
|
||||
},
|
||||
label: {
|
||||
type: "plain_text",
|
||||
text: "Reply",
|
||||
},
|
||||
},
|
||||
],
|
||||
submit: {
|
||||
type: "plain_text",
|
||||
text: "Submit",
|
||||
},
|
||||
},
|
||||
{
|
||||
validationSchema: z.object({
|
||||
replyInput: z.string().min(3).max(500),
|
||||
}),
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Note that the `block_id` of the input is used as the key in the validation schema (not the `action_id`).
|
||||
|
||||
The above example will show an error message if the user submits a reply that is less than 3 characters or more than 500 characters, but you might want to provide an even better experience by using the built-in validation provided by BlockKit:
|
||||
|
||||
```ts
|
||||
await slack.openView("Get the reply", event.trigger_id, {
|
||||
type: "modal",
|
||||
callback_id: "reply",
|
||||
title: {
|
||||
type: "plain_text",
|
||||
text: "Reply to Issue",
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
type: "input",
|
||||
block_id: "replyInput",
|
||||
element: {
|
||||
type: "plain_text_input",
|
||||
action_id: "reply",
|
||||
},
|
||||
label: {
|
||||
type: "plain_text",
|
||||
text: "Reply",
|
||||
},
|
||||
min_length: 3,
|
||||
max_length: 500,
|
||||
},
|
||||
],
|
||||
submit: {
|
||||
type: "plain_text",
|
||||
text: "Submit",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
See Slack's [Block Element reference docs](https://api.slack.com/reference/block-kit/block-elements) page for more information the properties you can use to control a user's input.
|
||||
|
||||
## JSX Slack
|
||||
|
||||
You can use the [JSX Slack](https://github.com/yhatt/jsx-slack/) project to build your views in a more declarative way:
|
||||
|
||||
### Step 1: Install and configure JSX Slack
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install jsx-slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add jsx-slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add jsx-slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
If you aren't already using React in your project, you will need to update your `tsconfig.json` file to add the `compilerOptions.jsx` option, and ensure to include `.tsx` files in your `include` array:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Create your Modal
|
||||
|
||||
```tsx modals.tsx
|
||||
/** @jsxImportSource jsx-slack */
|
||||
import JSXSlack, {
|
||||
Actions,
|
||||
Input,
|
||||
Textarea,
|
||||
Section,
|
||||
Header,
|
||||
Modal,
|
||||
} from "jsx-slack";
|
||||
|
||||
export function replyModal(title: string, callbackId: string) {
|
||||
return JSXSlack(
|
||||
<Modal title="Your reply" close="Cancel" callbackId={callbackId}>
|
||||
<Header>Issue title</Header>
|
||||
<Section>{title}</Section>
|
||||
<Header>Your reply</Header>
|
||||
<Textarea
|
||||
name="message"
|
||||
label="Message"
|
||||
placeholder="Your message"
|
||||
maxLength={500}
|
||||
id="messageInput"
|
||||
/>
|
||||
<Input type="submit" value="submit" />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Open the Modal
|
||||
|
||||
```ts
|
||||
import { replyModal } from "./modals";
|
||||
|
||||
await slack.openView(
|
||||
"Get the reply",
|
||||
event.trigger_id,
|
||||
replyModal("Issue title", "reply")
|
||||
);
|
||||
```
|
||||
|
||||
## Handling a View Submission
|
||||
|
||||
To get the results of a view submission, you can use the [viewSubmissionInteraction](../events/view-submission-interaction) event, providing the `callback_id` of the view you want to listen for:
|
||||
|
||||
```ts
|
||||
new Trigger({
|
||||
id: "handle-view-submission",
|
||||
name: "Handle View Submission",
|
||||
on: slack.events.viewSubmissionInteraction({
|
||||
callbackId: "reply",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
// use event.view.state.values to get the values of the inputs
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
For more information please see the [viewSubmissionInteraction docs](../events/view-submission-interaction).
|
||||
|
||||
## Passing custom data
|
||||
|
||||
There are a few ways you can pass custom data to your view submission handler when opening a view:
|
||||
|
||||
### Using the `metadata` option
|
||||
|
||||
When calling `openView`, you can pass a 4th argument which is object with a `metadata` property. This will be passed to your view submission handler as `event.view.private_metadata`:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts openView.ts
|
||||
import { replyModal } from "./modals";
|
||||
|
||||
await slack.openView(
|
||||
"Get the reply",
|
||||
event.trigger_id,
|
||||
replyModal("Issue title", "reply"),
|
||||
{
|
||||
metadata: {
|
||||
issueId: "123",
|
||||
thread_ts: event.message.ts,
|
||||
},
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
```ts viewSubmissionInteraction.ts
|
||||
new Trigger({
|
||||
id: "handle-view-submission",
|
||||
name: "Handle View Submission",
|
||||
on: slack.events.viewSubmissionInteraction({
|
||||
callbackId: "reply",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
// event.view.private_metadata will be:
|
||||
// {
|
||||
// issueId: "123",
|
||||
// thread_ts: "123.456"
|
||||
// }
|
||||
//
|
||||
// use event.view.private_metadata.thread_ts to post a reply to a message in a thread
|
||||
await slack.postMessage("Reply", {
|
||||
channelName: "github-issues",
|
||||
text: event.view.state.values.messageInput.message.value,
|
||||
thread_ts: event.view.private_metadata.thread_ts,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="trigger_id" type="string" required={true}>
|
||||
The trigger ID from the original event. Must be called within 3 seconds of the
|
||||
original event.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="view" type="view object" required={true}>
|
||||
The view to open.
|
||||
|
||||
<Expandable title="properties">
|
||||
<ParamField path="type" type="string" required={true}>
|
||||
Must be `modal`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="callback_id" type="string" required={false}>
|
||||
A unique identifier for the view. You can use this when you trigger on the [viewSubmissionInteraction](../events/view-submission-interaction) event. If not specified, a unique identifier will be generated. Maximum length for this field is 255 characters.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="title" type="plain_text object" required={true}>
|
||||
The title that appears in the top-left of the modal. Must be a plain_text text element with a max length of 24 characters.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="blocks" type="Array<block>" required={true}>
|
||||
An array of [blocks](https://api.slack.com/reference/block-kit/blocks) that defines the content of the view. Max of 100 blocks.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="submit_disabled" type="boolean">
|
||||
Whether the submit button is disabled until the user makes changes to the view. Defaults to `false`.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="options" type="object" required={false}>
|
||||
<Expandable title="properties">
|
||||
<ParamField path="validationSchema" type="ZodObject" required={false}>
|
||||
A [Zod](/guides/zod) object schema to validate the view submission. If the schema fails, the view submission will be rejected and the user will be shown an error message.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="onSubmit" type="string" required={false}>
|
||||
One of `"clear" | "close" | "none"` to specify what happens after the view is submitted. Defaults to `"close"`. `"clear"` will clear all the modals in the stack, `"close"` will close the current modal, and `"none"` will do nothing.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="metadata" type="object" required={false}>
|
||||
A custom object that will be passed to the [viewSubmissionInteraction](../events/view-submission-interaction) event as `event.view.private_metadata`.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="ok" type="boolean" default="true">
|
||||
Always true; non-ok responses will halt the workflow run and throw an error.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="view" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="id" type="string">
|
||||
The unique ID of the view. You can use this to update the view later.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="team_id" type="string">
|
||||
The ID of the workspace where the view was opened.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="type" type="string">
|
||||
The type of view. Always `modal`.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="private_metadata" type="object">
|
||||
The metadata that was passed to the view when it was opened.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="callback_id" type="string">
|
||||
The callback ID that was passed to the view when it was opened.
|
||||
</ResponseField>
|
||||
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflow
|
||||
|
||||
The following example combines WhatsApp and Slack to create a workflow that allows you to receive WhatsApp messages in Slack, and use a modal to compose a reply.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```tsx whatsappToSlack.tsx
|
||||
/** @jsxImportSource jsx-slack */
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import {
|
||||
events,
|
||||
sendText,
|
||||
getMediaUrl,
|
||||
MessageEventMessage,
|
||||
} from "@trigger.dev/whatsapp";
|
||||
import JSXSlack, {
|
||||
Actions,
|
||||
Blocks,
|
||||
Button,
|
||||
Section,
|
||||
Header,
|
||||
Context,
|
||||
Image,
|
||||
Modal,
|
||||
Input,
|
||||
Textarea,
|
||||
} from "jsx-slack";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat("en-US", {
|
||||
timeStyle: "short",
|
||||
dateStyle: "short",
|
||||
});
|
||||
|
||||
// this trigger listens for WhatsApp messages and sends them to Slack
|
||||
new Trigger({
|
||||
id: "whatsapp-to-slack",
|
||||
name: "WhatsApp: load messages",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//this generates Slack blocks from the WhatsApp message
|
||||
const messageBody = await createMessageBody(event.message);
|
||||
|
||||
await slack.postMessage("jsx-test", {
|
||||
channelName: "whatsapp-support",
|
||||
//text appears in Slack notifications on mobile/desktop
|
||||
text: "How is your progress today?",
|
||||
//import and use JSXSlack to make creating rich messages much easier
|
||||
blocks: JSXSlack(
|
||||
<Blocks>
|
||||
<Header>From: {event.message.from}</Header>
|
||||
<Context>At: {dateFormatter.format(event.message.timestamp)}</Context>
|
||||
{messageBody}
|
||||
<Actions blockId="launch-modal">
|
||||
<Button value="reply" actionId="reply">
|
||||
Reply
|
||||
</Button>
|
||||
</Actions>
|
||||
</Blocks>
|
||||
),
|
||||
//pass the WhatsApp message to the next trigger
|
||||
metadata: {
|
||||
whatsAppMessage: event.message,
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```tsx replyButtonInteraction.tsx
|
||||
//this trigger creates a Slack modal when a user presses the Reply button
|
||||
new Trigger({
|
||||
id: "whatsapp-to-slack-modal",
|
||||
name: "WhatsApp: show message composer",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "launch-modal",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (!event.trigger_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
//get the action (pressing the reply button) and the original WhatsApp message
|
||||
const action = event.actions[0];
|
||||
const whatsAppMessage =
|
||||
event.message?.metadata?.event_payload.whatsAppMessage;
|
||||
|
||||
//generate Slack blocks from the WhatsApp message
|
||||
const messageBody = await createMessageBody(whatsAppMessage);
|
||||
|
||||
if (action.action_id === "reply" && action.type === "button") {
|
||||
//show a reply modal, with the original message and an input field for the reply
|
||||
await slack.openView(
|
||||
"Opening view",
|
||||
event.trigger_id,
|
||||
JSXSlack(
|
||||
<Modal title="Your reply" close="Cancel" callbackId="submit-message">
|
||||
<Header>Original message</Header>
|
||||
{messageBody}
|
||||
<Header>Your reply</Header>
|
||||
<Textarea
|
||||
name="message"
|
||||
label="Message"
|
||||
placeholder="Your message"
|
||||
maxLength={500}
|
||||
id="messageField"
|
||||
/>
|
||||
<Input type="submit" value="submit" />
|
||||
</Modal>
|
||||
),
|
||||
{
|
||||
onSubmit: "close",
|
||||
//pass the original WhatsApp message to the next trigger, and the original Slack message so we can thread replies
|
||||
metadata: {
|
||||
whatsAppMessage,
|
||||
thread_ts: event.message?.ts,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```tsx replyModalSubmission.tsx
|
||||
//this trigger sends the reply from Slack to WhatsApp
|
||||
new Trigger({
|
||||
id: "whatsapp-composed-slack-message",
|
||||
name: "WhatsApp: send message from Slack",
|
||||
on: slack.events.viewSubmissionInteraction({
|
||||
callbackId: "submit-message",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("Modal submission", { event });
|
||||
|
||||
//the message from the input field in Slack
|
||||
const usersResponse = event.view.state?.values.messageField.message
|
||||
.value as string;
|
||||
|
||||
//get the data from the previous messages/panels
|
||||
const privateMetadata =
|
||||
event.view.private_metadata && JSON.parse(event.view.private_metadata);
|
||||
await ctx.logger.info("Private metadata", privateMetadata);
|
||||
const whatsAppMessage = privateMetadata?.whatsAppMessage;
|
||||
|
||||
if (!whatsAppMessage || !usersResponse) {
|
||||
await ctx.logger.error("No message or original message", { event });
|
||||
return;
|
||||
}
|
||||
|
||||
//send WhatsApp message
|
||||
await sendText("send-whatsapp", {
|
||||
fromId: "102119172798864",
|
||||
to: whatsAppMessage.from,
|
||||
text: usersResponse,
|
||||
});
|
||||
|
||||
//send message in the Slack thread
|
||||
await slack.postMessage("slack-reply", {
|
||||
channelName: "whatsapp-support",
|
||||
text: `Replied with: ${usersResponse}`,
|
||||
blocks: JSXSlack(
|
||||
<Blocks>
|
||||
<Header>Reply from @{event.user.username}</Header>
|
||||
<Context>
|
||||
At: {dateFormatter.format(new Date())} To: {whatsAppMessage.from}
|
||||
</Context>
|
||||
<Section>{usersResponse}</Section>
|
||||
</Blocks>
|
||||
),
|
||||
thread_ts: privateMetadata?.thread_ts,
|
||||
});
|
||||
|
||||
return event;
|
||||
},
|
||||
}).listen();
|
||||
|
||||
//creates different Slack blocks depending on the type of WhatsApp message (e.g. text, image, etc.)
|
||||
async function createMessageBody(message: MessageEventMessage) {
|
||||
switch (message.type) {
|
||||
case "text": {
|
||||
return <Section>{message.text.body}</Section>;
|
||||
}
|
||||
case "image": {
|
||||
const mediaUrl = await getMediaUrl(`getImageUrl`, message.image);
|
||||
return (
|
||||
<Image
|
||||
src={mediaUrl}
|
||||
alt={message.image.caption ?? ""}
|
||||
title={message.image.caption ?? ""}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "video": {
|
||||
const mediaUrl = await getMediaUrl(`getVideoUrl`, message.video);
|
||||
return <Section>{mediaUrl}</Section>;
|
||||
}
|
||||
default:
|
||||
return <Section>Unsupported message type: {message.type}</Section>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,113 +0,0 @@
|
||||
---
|
||||
title: "Post Message Response"
|
||||
sidebarTitle: "Post Message Response"
|
||||
description: "Post a Slack message in response to a user interaction in Slack"
|
||||
---
|
||||
|
||||
Post a message to slack when you receive a [blockActionInteraction](../events/block-action-interaction) event with a `response_url`. For example, if you publish a message with a button and the user clicks the button, you can use this action to post a message in response to the user's click.
|
||||
|
||||
There are three different types of responses you can send:
|
||||
|
||||
- **Ephemeral**: A message that only the user who clicked the button will see and do not persist in the channel or across apps. This is the default.
|
||||
- **In Channel**: A message that will be published to the channel and will persist across apps. Everyone in the channel will see the message.
|
||||
- **Update**: Update the original message with new text or blocks.
|
||||
|
||||
Here's a table with the different `message` params you can use for each type of response (`text` and `blocks` are supported for all three types of responses)
|
||||
|
||||
| Param | Ephemeral | In Channel | Update |
|
||||
| ------------------ | ----------- | -------------- | ----------- |
|
||||
| `replace_original` | `false` | `false` | `true` |
|
||||
| `response_type` | `undefined` | `"in_channel"` | `undefined` |
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="text" type="string" required={true}>
|
||||
The formatted text of the message to be published, formatted as [mrkdwn](https://api.slack.com/reference/surfaces/formatting#basics).
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="blocks" type="object" required={false}>
|
||||
You can use blocks to create a rich message with images, buttons, and more.
|
||||
|
||||
You can either pass in a JavaScript object or use [JSX Slack](https://github.com/yhatt/jsx-slack/) to create blocks. We highly recommend using JSX Slack as it's much easier to read and write. See the [block example](#blocks-with-interactivity) to see it in action.
|
||||
|
||||
For full details on Slack blocks, see the [Slack API docs](https://api.slack.com/reference/block-kit/blocks).
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="response_type" type="'in_channel' | undefined" required={false}>
|
||||
Set the `'in_channel'` response type to publish the message to the channel. If not specified, the message will be ephemeral.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="replace_original" type="boolean" required={false} default="false">
|
||||
Set to `true` to update the original message with new text or blocks. If not specified, the message will be ephemeral or published to the channel.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="delete_original" type="boolean" required={false} default="false">
|
||||
Set to `true` to delete the original message.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="thread_ts" type="string" required={false}>
|
||||
The "timestamp ID" of the message to reply to. If not specified, the
|
||||
message will be published as a new thread.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="ok" type="boolean" default="true">
|
||||
Always true; non-ok responses will halt the workflow run and throw an error.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts triggers.ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import { z } from "zod";
|
||||
|
||||
new Trigger({
|
||||
id: "slack-block-interaction",
|
||||
name: "Slack Block Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "issue.action.block",
|
||||
actionId: ["status-blocked", "status-help", "rating"],
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (!event.response_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Post an ephemeral message
|
||||
return slack.postMessageResponse(
|
||||
"Added a comment to the issue",
|
||||
event.response_url,
|
||||
{
|
||||
text: `You rated your day ${action.selected_option?.value} stars`,
|
||||
replace_original: false,
|
||||
}
|
||||
);
|
||||
|
||||
// Post an a message to the channel
|
||||
return slack.postMessageResponse(
|
||||
"Added a comment to the issue",
|
||||
event.response_url,
|
||||
{
|
||||
text: `Another rating of ${action.selected_option?.value} stars!`,
|
||||
response_type: "in_channel",
|
||||
}
|
||||
);
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,291 +0,0 @@
|
||||
---
|
||||
title: "Post Message"
|
||||
sidebarTitle: "Post Message"
|
||||
description: "Post a message to a Slack channel"
|
||||
---
|
||||
|
||||
Publish Slack messages to a public or private channel in your Slack Workspace as the Trigger.dev Slack bot. If you need to publish messages to your customer's Slack channels, consider using [Incoming Webhooks](https://api.slack.com/messaging/webhooks) and our [fetch](/functions/fetch) function.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="channelName" type="string" required={false}>
|
||||
The name of the channel, can optionally include the `#`. E.g. `#team`.
|
||||
Alternatively you can use the `channelId` param.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="channelId" type="string" required={false}>
|
||||
The slack ID of the channel, e.g. `C04GWUTDC4W`. Can be used instead of `channelName`. Use `channelId` if the slack channel name could change.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="text" type="string" required={true}>
|
||||
The formatted text of the message to be published, formatted as [mrkdwn](https://api.slack.com/reference/surfaces/formatting#basics).
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="blocks" type="object" required={false}>
|
||||
You can use blocks to create a rich message with images, buttons, and more.
|
||||
|
||||
You can either pass in a JavaScript object or use [JSX Slack](https://github.com/yhatt/jsx-slack/) to create blocks. We highly recommend using JSX Slack as it's much easier to read and write. See the [block example](#blocks-with-interactivity) to see it in action.
|
||||
|
||||
For full details on Slack blocks, see the [Slack API docs](https://api.slack.com/reference/block-kit/blocks).
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="thread_ts" type="string" required={false}>
|
||||
The "timestamp ID" of the message to reply to. If not specified, the
|
||||
message will be published as a new thread.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="metadata" type="object" required={false}>
|
||||
A JSON object that will be attached to the message. This can be used to
|
||||
store custom data about the message, but will not be displayed to users. Useful for passing data to a [blockActionInteraction](../events/block-action-interaction) trigger.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="username" type="string" required={false}>
|
||||
The name of the bot that will publish the message. If not specified, the
|
||||
message will be published as the Trigger.dev Slack bot.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="icon_emoji" type="string" required={false}>
|
||||
The emoji to use as the icon for the bot that will publish the message.
|
||||
If not specified, the message will be published as the Trigger.dev Slack
|
||||
bot.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="icon_url" type="string" required={false}>
|
||||
The URL of an image to use as the icon for the bot that will publish the
|
||||
message. If not specified, the message will be published as the
|
||||
Trigger.dev Slack bot.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="ok" type="boolean" default="true">
|
||||
Always true; non-ok responses will halt the workflow run and throw an error.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="channel" type="string">
|
||||
The channel ID of the channel the message was published to.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="ts" type="string">
|
||||
The "timestamp ID" of the message, which can be used to update or delete the
|
||||
message.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="message" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="ts" type="string">
|
||||
The "timestamp ID" of the message, which can be used to update or delete the message.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="text" type="string">
|
||||
The text published to the channel.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="user" type="string">
|
||||
The user ID of the user who published the message.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="bot_id" type="string">
|
||||
The bot ID of the bot that published the message.
|
||||
</ResponseField>
|
||||
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Notify Slack on New GitHub Star
|
||||
import * as github from "@trigger.dev/github";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
id: "new-star",
|
||||
name: "On New Star",
|
||||
on: github.events.newStarEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await slack.postMessage("⭐️ New Star", {
|
||||
channelName: "github-stars",
|
||||
text: `Repo ${event.repository.full_name} got a star from ${event.sender.login}, for a total of ${event.repository.stargazers_count} stars!`,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"ok": true,
|
||||
"ts": "1673618429.084699",
|
||||
"channel": "C04GWUTDC3W",
|
||||
"message": {
|
||||
"ts": "1673618429.084699",
|
||||
"text": "New domain created: trigger.dev by customer 1st-ever-slack-workflow-yippie",
|
||||
"type": "message",
|
||||
"user": "U04JTTQ08SF",
|
||||
"bot_id": "B04JR3DCB4M"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
### Blocks with interactivity
|
||||
|
||||
You can add interaction and richer visual elements using Blocks. The easiest way to add them is using `jsx-slack` (which is a separate npm package that you can install).
|
||||
|
||||
This example messages your team every minute (!) and asks them how they're doing. There are two buttons and a dropdown menu.
|
||||
|
||||
In this examples there are two workflows:
|
||||
|
||||
1. Messages your team every minute (!) and asks them how they're doing.
|
||||
2. Receives the interaction from users. It adds reactions when the buttons are pressed and posts a message when a user selects from the dropdown menu.
|
||||
|
||||
Please note, that to use `jsx-slack` you will need to add the `jsxImportSource` pragma to the top of your file. This is because `jsx-slack` is not a React library, but it uses the same syntax as React. Also, you might need to add `"jsx": "react-jsx"` to your `compilerOption` in `tsconfig.json`. The workflow file needs to be a `.jsx` or `.tsx` file (like when you use React).
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript workflow.tsx
|
||||
/** @jsxImportSource jsx-slack */
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import JSXSlack, {
|
||||
Actions,
|
||||
Blocks,
|
||||
Button,
|
||||
Section,
|
||||
Select,
|
||||
Option,
|
||||
} from "jsx-slack";
|
||||
import { z } from "zod";
|
||||
|
||||
const BLOCK_ID = "issue.action.block";
|
||||
|
||||
//1. every minute see how your employees are doing, we don't recommend this frequency 😉
|
||||
new Trigger({
|
||||
id: "slack-interactivity",
|
||||
name: "Testing Slack Interactivity",
|
||||
on: scheduleEvent({
|
||||
rateOf: {
|
||||
minutes: 1,
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await slack.postMessage("jsx-test", {
|
||||
channelName: "test-integrations",
|
||||
//text appears in Slack notifications on mobile/desktop
|
||||
text: "How is your progress today?",
|
||||
//import and use JSXSlack to make creating rich messages much easier
|
||||
blocks: JSXSlack(
|
||||
<Blocks>
|
||||
<Section>How is your progress today?</Section>
|
||||
<Actions blockId={BLOCK_ID}>
|
||||
<Button value="blocked" actionId="status-blocked">
|
||||
I'm blocked
|
||||
</Button>
|
||||
<Button
|
||||
value="help"
|
||||
actionId="status-help"
|
||||
url="https://xkcd.com/1349/"
|
||||
>
|
||||
Get help
|
||||
</Button>
|
||||
<Select actionId="rating" placeholder="Rate it!">
|
||||
<Option value="5">5 {":star:".repeat(5)}</Option>
|
||||
<Option value="4">4 {":star:".repeat(4)}</Option>
|
||||
<Option value="3">3 {":star:".repeat(3)}</Option>
|
||||
<Option value="2">2 {":star:".repeat(2)}</Option>
|
||||
<Option value="1">1 {":star:".repeat(1)}</Option>
|
||||
</Select>
|
||||
</Actions>
|
||||
</Blocks>
|
||||
),
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
|
||||
//2. this workflow listens for Slack interactions filtered by the block id and actions we used above
|
||||
new Trigger({
|
||||
id: "slack-block-interaction",
|
||||
name: "Slack Block Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: BLOCK_ID,
|
||||
actionId: ["status-blocked", "status-help", "rating"],
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//create promises from all the actions
|
||||
const promises = event.actions.map((action) => {
|
||||
switch (action.action_id) {
|
||||
case "status-blocked": {
|
||||
//the user is blocked so add a 😢 emoji as a reaction
|
||||
if (event.message) {
|
||||
return slack.addReaction("React to message", {
|
||||
name: "cry",
|
||||
timestamp: event.message.ts,
|
||||
channelId: event.channel.id,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "status-help": {
|
||||
//the user needs help so add an 🆘 emoji as a reaction
|
||||
if (event.message) {
|
||||
return slack.addReaction("React to message", {
|
||||
name: "sos",
|
||||
timestamp: event.message.ts,
|
||||
channelId: event.channel.id,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "rating": {
|
||||
if (action.type != "static_select") {
|
||||
throw new Error("This action should be a select");
|
||||
}
|
||||
|
||||
//post the rating as a message that appears below the original,
|
||||
//only the user pressing the button will see this message
|
||||
return slack.postMessageResponse(
|
||||
"Added a comment to the issue",
|
||||
event.response_url,
|
||||
{
|
||||
text: `You rated your day ${action.selected_option?.value} stars`,
|
||||
replace_original: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
default:
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json tsconfig.json
|
||||
{
|
||||
//other options
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
//other options
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"] // make sure to include `.tsx` files
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,478 +0,0 @@
|
||||
---
|
||||
title: "Block Actions"
|
||||
sidebarTitle: "Block Actions"
|
||||
description: "Trigger a workflow when a user interacts with a BlockKit interaction component (e.g. buttons, menus, etc.)"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
If you send a message with BlockKit components, you can trigger a workflow when a user interacts with those components. For example, you can trigger a workflow when a user clicks a button, selects an option from a menu, or submits a modal.
|
||||
|
||||
The event will be the [block_action event payload](https://api.slack.com/reference/interaction-payloads/block-actions#fields) from Slack, which includes the `actions` array. You can use the `actions` array to determine which action was triggered, and the `block_id` and `action_id` to determine which component was interacted with.
|
||||
|
||||
A very simple example would be to first send a message to a channel with a button, and then trigger a workflow when the button is clicked:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Send Message with Button
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import { z } from "zod";
|
||||
|
||||
const BLOCK_ID = "employee-ping";
|
||||
|
||||
new Trigger({
|
||||
id: "send-message-with-button",
|
||||
name: "Send Message with Button",
|
||||
on: scheduleEvent({
|
||||
rateOf: {
|
||||
minutes: 5,
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await slack.postMessage("Are you still there?", {
|
||||
channelName: "employee-ping",
|
||||
//text appears in Slack notifications on mobile/desktop
|
||||
text: "Are you still there?",
|
||||
blocks: [
|
||||
{
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: "Are you still there?",
|
||||
verbatim: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "actions",
|
||||
block_id: BLOCK_ID, // this is the block_id that we'll use to identify the message
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
action_id: "nope",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "I'm at lunch",
|
||||
emoji: true,
|
||||
},
|
||||
value: "lunch",
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
action_id: "youbet",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "Still here!",
|
||||
emoji: true,
|
||||
},
|
||||
value: "in-my-seat",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```typescript Listen for Button Click
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import { z } from "zod";
|
||||
|
||||
const BLOCK_ID = "employee-ping";
|
||||
|
||||
new Trigger({
|
||||
id: "employee-ping-event",
|
||||
name: "Listen for Employee Ping",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: BLOCK_ID,
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const action = event.actions[0];
|
||||
|
||||
if (action.action_id === "nope") {
|
||||
await slack.postMessage("respond to employee", {
|
||||
channelName: "employee-ping",
|
||||
text: "Okay, I'll ping you again in 5 minutes.",
|
||||
});
|
||||
} else if (action.action_id === "youbet") {
|
||||
await slack.postMessage("respond to employee", {
|
||||
channelName: "employee-ping",
|
||||
text: "Great! I'll ping you again in 5 minutes.",
|
||||
});
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Passing custom data
|
||||
|
||||
There are three ways to pass custom data to the workflow that is triggered by the event:
|
||||
|
||||
1. Use the `value` field of the BlockKit component. This is the easiest way to pass data, but it is limited to 2000 characters.
|
||||
2. Use the `metadata` option when sending the message. This is best for handling "context" data that relates to any possible action taken in a BlockKit message.
|
||||
|
||||
An example of using the `value` field:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts postMessage.ts
|
||||
await slack.postMessage("New Issue", {
|
||||
channelName: "github-issues",
|
||||
//text appears in Slack notifications on mobile/desktop
|
||||
text: "There is a new GitHub issue in the repo",
|
||||
blocks: [
|
||||
{
|
||||
type: "actions",
|
||||
block_id: "new.issue", // this is the block_id that we'll use to identify the message
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
action_id: "reply",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "Reply to Issue",
|
||||
},
|
||||
value: githubIssueId,
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
action_id: "close",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "Close Issue",
|
||||
},
|
||||
value: githubIssueId,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
```ts trigger.ts
|
||||
new Trigger({
|
||||
id: "github-issue-slack-interaction",
|
||||
name: "GitHub Issue Slack Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "new.issue",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const action = event.actions[0];
|
||||
|
||||
if (action.action_id === "reply") {
|
||||
// action.value is the githubIssueId
|
||||
} else if (action.action_id === "close") {
|
||||
// action.value is the githubIssueId
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
And an example using the `metadata` option (which can be any JSON-serializable data):
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts postMessage.ts
|
||||
await slack.postMessage("New Issue", {
|
||||
channelName: "github-issues",
|
||||
//text appears in Slack notifications on mobile/desktop
|
||||
text: "There is a new GitHub issue in the repo",
|
||||
metadata: { githubIssueId },
|
||||
blocks: [
|
||||
{
|
||||
type: "actions",
|
||||
block_id: "new.issue", // this is the block_id that we'll use to identify the message
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
action_id: "reply",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "Reply to Issue",
|
||||
},
|
||||
value: "reply",
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
action_id: "close",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "Close Issue",
|
||||
},
|
||||
value: "close",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
```ts trigger.ts
|
||||
new Trigger({
|
||||
id: "github-issue-slack-interaction",
|
||||
name: "GitHub Issue Slack Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "new.issue",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
const action = event.actions[0];
|
||||
|
||||
if (action.action_id === "reply") {
|
||||
// event.message.metadata.event_payload.githubIssueId is the githubIssueId
|
||||
} else if (action.action_id === "close") {
|
||||
// event.message.metadata.event_payload.githubIssueId is the githubIssueId
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## JSX Slack
|
||||
|
||||
You can use the [JSX Slack](https://github.com/yhatt/jsx-slack/) project to build your BlockKit messages and trigger the `blockActionInteraction` event.
|
||||
|
||||
### Step 1: Install and configure JSX Slack
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
|
||||
```bash
|
||||
npm install jsx-slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
|
||||
```bash
|
||||
pnpm add jsx-slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="yarn">
|
||||
|
||||
```bash
|
||||
yarn add jsx-slack
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
If you aren't already using React in your project, you will need to update your `tsconfig.json` file to add the `compilerOptions.jsx` option, and ensure to include `.tsx` files in your `include` array:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Create your BlockKit message
|
||||
|
||||
```tsx
|
||||
/** @jsxImportSource jsx-slack */
|
||||
import JSXSlack, {
|
||||
Actions,
|
||||
Blocks,
|
||||
Button,
|
||||
Section,
|
||||
Select,
|
||||
Option,
|
||||
} from "jsx-slack";
|
||||
|
||||
export function progressBlock(blockId: string) {
|
||||
return JSXSlack(
|
||||
<Blocks>
|
||||
<Section>How is your progress today?</Section>
|
||||
<Actions blockId={blockId}>
|
||||
<Button value="blocked" actionId="status-blocked">
|
||||
I'm blocked
|
||||
</Button>
|
||||
<Button
|
||||
value="help"
|
||||
actionId="status-help"
|
||||
url="https://xkcd.com/1349/"
|
||||
>
|
||||
Get help
|
||||
</Button>
|
||||
<Select actionId="rating" placeholder="Rate it!">
|
||||
<Option value="5">5 {":star:".repeat(5)}</Option>
|
||||
<Option value="4">4 {":star:".repeat(4)}</Option>
|
||||
<Option value="3">3 {":star:".repeat(3)}</Option>
|
||||
<Option value="2">2 {":star:".repeat(2)}</Option>
|
||||
<Option value="1">1 {":star:".repeat(1)}</Option>
|
||||
</Select>
|
||||
</Actions>
|
||||
</Blocks>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Please note, that to use `jsx-slack` you will need to add the `jsxImportSource` pragma to the top of your file. This is because `jsx-slack` is not a React library, but it uses the same syntax as React. The file also needs to be a `.jsx` or `.tsx` file (like when you use React).
|
||||
|
||||
### Step 3: Use your BlockKit message in a `postMessage` call
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript postMessage.ts
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import { z } from "zod";
|
||||
import { progressBlock } from "./messages";
|
||||
|
||||
const BLOCK_ID = "issue.action.block";
|
||||
|
||||
//1. every minute see how your employees are doing, we don't recommend this frequency 😉
|
||||
new Trigger({
|
||||
id: "slack-interactivity",
|
||||
name: "Testing Slack Interactivity",
|
||||
on: scheduleEvent({
|
||||
rateOf: {
|
||||
minutes: 1,
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await slack.postMessage("jsx-test", {
|
||||
channelName: "employee-progress",
|
||||
text: "How is your progress today?",
|
||||
blocks: progressBlock(BLOCK_ID), // Pass in the block_id which we'll trigger on in the next step
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```typescript blockAction.ts
|
||||
new Trigger({
|
||||
id: "slack-block-interaction",
|
||||
name: "Slack Block Interaction",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: BLOCK_ID, // trigger on the block_id we passed in the previous step
|
||||
actionId: ["status-blocked", "status-help", "rating"], // we could have also left this blank to trigger on all actions
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (!event.message) {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = event.actions[0];
|
||||
|
||||
switch (action.action_id) {
|
||||
case "status-blocked": {
|
||||
return slack.addReaction("React to message", {
|
||||
name: "cry",
|
||||
timestamp: event.message.ts,
|
||||
channelId: event.channel.id,
|
||||
});
|
||||
}
|
||||
case "status-help": {
|
||||
return slack.addReaction("React to message", {
|
||||
name: "sos",
|
||||
timestamp: event.message.ts,
|
||||
channelId: event.channel.id,
|
||||
});
|
||||
}
|
||||
case "rating": {
|
||||
if (action.type != "static_select") {
|
||||
throw new Error("This action should be a select");
|
||||
}
|
||||
|
||||
//post the rating as a message that appears below the original,
|
||||
//only the user pressing the button will see this message
|
||||
return slack.postMessageResponse(
|
||||
"Added a comment to the issue",
|
||||
event.response_url,
|
||||
{
|
||||
text: `You rated your day ${action.selected_option?.value} stars`,
|
||||
replace_original: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="blockId" type="string" required={true}>
|
||||
The `block_id` of the BlockKit component that you want to listen for.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="actionId" type="string | string[]" required={false}>
|
||||
The `action_id` of the BlockKit component that you want to listen for. If you
|
||||
don't specify an `actionId`, the workflow will be triggered for any action on
|
||||
the specified `blockId`. You can also specify an array of `action_id`s to
|
||||
listen for multiple actions.
|
||||
</ParamField>
|
||||
|
||||
## Event Payload
|
||||
|
||||
Please see the [Slack Block Actions event payload](https://api.slack.com/reference/interaction-payloads/block-actions#fields) for more information.
|
||||
|
||||
<ResponseField name="type" type="string">
|
||||
The type of event. This will always be `block_actions`.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="trigger_id" type="string">
|
||||
A short-lived ID that can be used to open a modal. See the [openView
|
||||
docs](../actions/open-view)
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="response_url" type="string">
|
||||
A short-lived URL that can be used to send a response to the user. See the
|
||||
[postMessageResponse docs](../actions/post-message-response) for more
|
||||
information.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="user" type="user object">
|
||||
The user that triggered the event.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="message" type="message object">
|
||||
The message that the user interacted with.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="view" type="view object">
|
||||
The view that the user interacted with.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="actions" type="Array<action>">
|
||||
An array of actions that the user interacted with. `actions.action_id` can be
|
||||
used to determine which action was triggered. (e.g. which button was clicked)
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="team" type="team object">
|
||||
The team that the user is a part of.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="channel" type="channel object">
|
||||
The channel where the interaction took place.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="container" type="object">
|
||||
<Expandable title="properties">
|
||||
<ResponseField name="type" type="string">
|
||||
The type of container. This will always be `message`.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="message_ts" type="string">
|
||||
The timestamp of the message that the user interacted with.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="channel_id" type="string">
|
||||
The ID of the channel where the interaction took place.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="is_ephemeral" type="boolean">
|
||||
Whether the message is ephemeral.
|
||||
</ResponseField>
|
||||
|
||||
</Expandable>
|
||||
</ResponseField>
|
||||
@@ -1,326 +0,0 @@
|
||||
---
|
||||
title: "View Submission"
|
||||
sidebarTitle: "View Submission"
|
||||
description: "Trigger a workflow when a user submits a modal view."
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
If you open a modal view with a submit button, you can trigger a workflow when the user submits the view using this trigger. See the [openView docs](../actions/open-view) for more information on how to open a modal view.
|
||||
|
||||
The event will be the [view_submission event payload](https://api.slack.com/reference/interaction-payloads/views#view_submission) from Slack, which includes the `view.state.values` object which you can use to access the values of the inputs in the view.
|
||||
|
||||
For example, given the following view:
|
||||
|
||||
```ts
|
||||
await slack.openView("Get the reply", event.trigger_id, {
|
||||
type: "modal",
|
||||
callback_id: "message-reply",
|
||||
title: {
|
||||
type: "plain_text",
|
||||
text: "Reply to Issue",
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
type: "input",
|
||||
block_id: "replyInput",
|
||||
element: {
|
||||
type: "plain_text_input",
|
||||
action_id: "reply",
|
||||
},
|
||||
label: {
|
||||
type: "plain_text",
|
||||
text: "Reply",
|
||||
},
|
||||
},
|
||||
],
|
||||
submit: {
|
||||
type: "plain_text",
|
||||
text: "Submit",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The event payload would have the following shape:
|
||||
|
||||
```json
|
||||
{
|
||||
// ...
|
||||
"view": {
|
||||
"id": "V04N2P0G797",
|
||||
"type": "modal",
|
||||
"state": {
|
||||
"values": {
|
||||
"replyInput": {
|
||||
"reply": {
|
||||
"type": "plain_text_input",
|
||||
"value": "This is the reply!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Callback IDs
|
||||
|
||||
You can optionally provide callback ID for the view in order to only trigger on specific views. The callback ID is specified in the `callback_id` property of the view. In the example above, the callback ID is `"message-reply"`:
|
||||
|
||||
```ts
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
on: slack.events.viewSubmissionInteraction({
|
||||
callbackId: "message-reply",
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
You can also provide an array of callback IDs to trigger on multiple views:
|
||||
|
||||
```ts
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
on: slack.events.viewSubmissionInteraction({
|
||||
callbackId: ["message-reply", "another-view"],
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
Because of the way the Slack API works, you cannot update the view or push a new view through the API when handling a view submission. The only way to update or push a view in a view submission interaction is with a [response_action](https://api.slack.com/surfaces/modals/using#updating_response), which we currently do not support. If you'd like this feature, please don't hesitate to [get in touch!](/get-help)
|
||||
|
||||
## Event payload
|
||||
|
||||
Please see the [Slack View Submission event payload](https://api.slack.com/reference/interaction-payloads/views#view_submission) for more information.
|
||||
|
||||
<ResponseField name="type" type="string">
|
||||
The type of event, which will always be `view_submission`.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="view" type="view object">
|
||||
The view that the user interacted with.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="user" type="user object">
|
||||
The user that submitted the view.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="team" type="team object">
|
||||
The team that the user is a part of.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="channel" type="channel object">
|
||||
The channel where the interaction took place.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflow
|
||||
|
||||
The following example combines WhatsApp and Slack to create a workflow that allows you to receive WhatsApp messages in Slack, and use a modal to compose a reply.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```tsx whatsappToSlack.tsx
|
||||
/** @jsxImportSource jsx-slack */
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import {
|
||||
events,
|
||||
sendText,
|
||||
getMediaUrl,
|
||||
MessageEventMessage,
|
||||
} from "@trigger.dev/whatsapp";
|
||||
import JSXSlack, {
|
||||
Actions,
|
||||
Blocks,
|
||||
Button,
|
||||
Section,
|
||||
Header,
|
||||
Context,
|
||||
Image,
|
||||
Modal,
|
||||
Input,
|
||||
Textarea,
|
||||
} from "jsx-slack";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat("en-US", {
|
||||
timeStyle: "short",
|
||||
dateStyle: "short",
|
||||
});
|
||||
|
||||
// this trigger listens for WhatsApp messages and sends them to Slack
|
||||
new Trigger({
|
||||
id: "whatsapp-to-slack",
|
||||
name: "WhatsApp: load messages",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//this generates Slack blocks from the WhatsApp message
|
||||
const messageBody = await createMessageBody(event.message);
|
||||
|
||||
await slack.postMessage("jsx-test", {
|
||||
channelName: "whatsapp-support",
|
||||
//text appears in Slack notifications on mobile/desktop
|
||||
text: "How is your progress today?",
|
||||
//import and use JSXSlack to make creating rich messages much easier
|
||||
blocks: JSXSlack(
|
||||
<Blocks>
|
||||
<Header>From: {event.message.from}</Header>
|
||||
<Context>At: {dateFormatter.format(event.message.timestamp)}</Context>
|
||||
{messageBody}
|
||||
<Actions blockId="launch-modal">
|
||||
<Button value="reply" actionId="reply">
|
||||
Reply
|
||||
</Button>
|
||||
</Actions>
|
||||
</Blocks>
|
||||
),
|
||||
//pass the WhatsApp message to the next trigger
|
||||
metadata: {
|
||||
whatsAppMessage: event.message,
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```tsx replyButtonInteraction.tsx
|
||||
//this trigger creates a Slack modal when a user presses the Reply button
|
||||
new Trigger({
|
||||
id: "whatsapp-to-slack-modal",
|
||||
name: "WhatsApp: show message composer",
|
||||
on: slack.events.blockActionInteraction({
|
||||
blockId: "launch-modal",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
if (!event.trigger_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
//get the action (pressing the reply button) and the original WhatsApp message
|
||||
const action = event.actions[0];
|
||||
const whatsAppMessage =
|
||||
event.message?.metadata?.event_payload.whatsAppMessage;
|
||||
|
||||
//generate Slack blocks from the WhatsApp message
|
||||
const messageBody = await createMessageBody(whatsAppMessage);
|
||||
|
||||
if (action.action_id === "reply" && action.type === "button") {
|
||||
//show a reply modal, with the original message and an input field for the reply
|
||||
await slack.openView(
|
||||
"Opening view",
|
||||
event.trigger_id,
|
||||
JSXSlack(
|
||||
<Modal title="Your reply" close="Cancel" callbackId="submit-message">
|
||||
<Header>Original message</Header>
|
||||
{messageBody}
|
||||
<Header>Your reply</Header>
|
||||
<Textarea
|
||||
name="message"
|
||||
label="Message"
|
||||
placeholder="Your message"
|
||||
maxLength={500}
|
||||
id="messageField"
|
||||
/>
|
||||
<Input type="submit" value="submit" />
|
||||
</Modal>
|
||||
),
|
||||
{
|
||||
onSubmit: "close",
|
||||
//pass the original WhatsApp message to the next trigger, and the original Slack message so we can thread replies
|
||||
metadata: {
|
||||
whatsAppMessage,
|
||||
thread_ts: event.message?.ts,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```tsx replyModalSubmission.tsx
|
||||
//this trigger sends the reply from Slack to WhatsApp
|
||||
new Trigger({
|
||||
id: "whatsapp-composed-slack-message",
|
||||
name: "WhatsApp: send message from Slack",
|
||||
on: slack.events.viewSubmissionInteraction({
|
||||
callbackId: "submit-message",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("Modal submission", { event });
|
||||
|
||||
//the message from the input field in Slack
|
||||
const usersResponse = event.view.state?.values.messageField.message
|
||||
.value as string;
|
||||
|
||||
//get the data from the previous messages/panels
|
||||
const privateMetadata =
|
||||
event.view.private_metadata && JSON.parse(event.view.private_metadata);
|
||||
await ctx.logger.info("Private metadata", privateMetadata);
|
||||
const whatsAppMessage = privateMetadata?.whatsAppMessage;
|
||||
|
||||
if (!whatsAppMessage || !usersResponse) {
|
||||
await ctx.logger.error("No message or original message", { event });
|
||||
return;
|
||||
}
|
||||
|
||||
//send WhatsApp message
|
||||
await sendText("send-whatsapp", {
|
||||
fromId: "102119172798864",
|
||||
to: whatsAppMessage.from,
|
||||
text: usersResponse,
|
||||
});
|
||||
|
||||
//send message in the Slack thread
|
||||
await slack.postMessage("slack-reply", {
|
||||
channelName: "whatsapp-support",
|
||||
text: `Replied with: ${usersResponse}`,
|
||||
blocks: JSXSlack(
|
||||
<Blocks>
|
||||
<Header>Reply from @{event.user.username}</Header>
|
||||
<Context>
|
||||
At: {dateFormatter.format(new Date())} To: {whatsAppMessage.from}
|
||||
</Context>
|
||||
<Section>{usersResponse}</Section>
|
||||
</Blocks>
|
||||
),
|
||||
thread_ts: privateMetadata?.thread_ts,
|
||||
});
|
||||
|
||||
return event;
|
||||
},
|
||||
}).listen();
|
||||
|
||||
//creates different Slack blocks depending on the type of WhatsApp message (e.g. text, image, etc.)
|
||||
async function createMessageBody(message: MessageEventMessage) {
|
||||
switch (message.type) {
|
||||
case "text": {
|
||||
return <Section>{message.text.body}</Section>;
|
||||
}
|
||||
case "image": {
|
||||
const mediaUrl = await getMediaUrl(`getImageUrl`, message.image);
|
||||
return (
|
||||
<Image
|
||||
src={mediaUrl}
|
||||
alt={message.image.caption ?? ""}
|
||||
title={message.image.caption ?? ""}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case "video": {
|
||||
const mediaUrl = await getMediaUrl(`getVideoUrl`, message.video);
|
||||
return <Section>{mediaUrl}</Section>;
|
||||
}
|
||||
default:
|
||||
return <Section>Unsupported message type: {message.type}</Section>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,94 +0,0 @@
|
||||
---
|
||||
title: "Send Audio Message"
|
||||
sidebarTitle: "Audio Message"
|
||||
description: "Post a audio message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp audio messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="url" type="string" required={true}>
|
||||
The url of the audio file to be sent.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={false}>
|
||||
Optionally, add the id of the message you want to reply to. It will appear as a reply in the WhatsApp chat.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendAudio } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an automatic audio reply to the message
|
||||
const audioResponse = await sendAudio("audio", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
url: "https://ssl.gstatic.com/dictionary/static/pronunciation/2022-03-02/audio/wi/wikipedia_en_gb_1.mp3",
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,103 +0,0 @@
|
||||
---
|
||||
title: "Send a Contacts Message"
|
||||
sidebarTitle: "Contacts Message"
|
||||
description: "Post a contacts message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp contacts messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="contacts" type="object" required={true}>
|
||||
An array of contacts to be sent.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendVideo } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an contacts message
|
||||
const contactsResponse = await sendContacts("contacts", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
contacts: [
|
||||
{
|
||||
name: {
|
||||
first_name: "Matt",
|
||||
last_name: "Aitken",
|
||||
formatted_name: "Matt Aitken",
|
||||
},
|
||||
phones: [
|
||||
{
|
||||
phone: "+12345678901",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,99 +0,0 @@
|
||||
---
|
||||
title: "Send Document Message"
|
||||
sidebarTitle: "Document Message"
|
||||
description: "Post a document message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp document messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="url" type="string" required={true}>
|
||||
The url of the document to be sent.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="caption" type="string" required={false}>
|
||||
Optional caption that sits below the video
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={false}>
|
||||
Optionally, add the id of the message you want to reply to. It will appear as a reply in the WhatsApp chat.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendDocument } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an automatic document reply to the message
|
||||
const documentResponse = await sendDocument("doc", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
url: "https://upload.wikimedia.org/wikipedia/commons/2/20/Re_example.pdf",
|
||||
caption: "A pdf for you",
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,99 +0,0 @@
|
||||
---
|
||||
title: "Send Image Message"
|
||||
sidebarTitle: "Image Message"
|
||||
description: "Post a image message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp image messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="url" type="string" required={true}>
|
||||
The url of the image to be sent.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="caption" type="string" required={false}>
|
||||
Optional caption that sits below the video
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={false}>
|
||||
Optionally, add the id of the message you want to reply to. It will appear as a reply in the WhatsApp chat.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendImage } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an automatic image reply to the message
|
||||
const imageResponse = await sendImage("image", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
url: "https://app.trigger.dev/emails/logo.png",
|
||||
caption: "This is a great caption",
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,109 +0,0 @@
|
||||
---
|
||||
title: "Send a Location Message"
|
||||
sidebarTitle: "Location Message"
|
||||
description: "Post a location message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp location messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="latitude" type="number" required={true}>
|
||||
The latitude of the location to be sent.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="longitude" type="number" required={true}>
|
||||
The latitude of the location to be sent.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="name" type="string" required={false}>
|
||||
Name of the location. An address must be specified for this to appear.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="address" type="string" required={false}>
|
||||
The address of the location, in a single string.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={false}>
|
||||
Optionally, add the id of the message you want to reply to. It will appear as a reply in the WhatsApp chat.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendVideo } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an location message
|
||||
const locationResponse = await sendLocation("location", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
latitude: 37.422,
|
||||
longitude: -122.084,
|
||||
name: "Trigger.dev HQ",
|
||||
address: "123 Main St, San Francisco, CA 94105",
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,95 +0,0 @@
|
||||
---
|
||||
title: "Send a Reaction Message"
|
||||
sidebarTitle: "Reaction Message"
|
||||
description: "Post a reaction to a WhatsApp message"
|
||||
---
|
||||
|
||||
Send WhatsApp reaction messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="emoji" type="string" required={true}>
|
||||
The emoji you want to react to the message with 🔥
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={true}>
|
||||
This is required: add the id of the message you want to reply to.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendVideo } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an automatic reaction to the message
|
||||
const reactionResponse = await sendReaction("reaction", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
isReplyTo: event.message.id,
|
||||
emoji: "🔥",
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,98 +0,0 @@
|
||||
---
|
||||
title: "Send a Sticker Message"
|
||||
sidebarTitle: "Sticker Message"
|
||||
description: "Post a sticker message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp sticker messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="url" type="string" required={true}>
|
||||
The url of the image to be sent. Please note that only webp files will work for stickers.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="caption" type="string" required={false}>
|
||||
Optional caption that sits below the video
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={false}>
|
||||
Optionally, add the id of the message you want to reply to. It will appear as a reply in the WhatsApp chat.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendVideo } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an automatic sticker to the message
|
||||
const stickerResponse = await sendSticker("stick", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
url: "https://www.tyntec.com/sites/default/files/2020-07/tyntec_rocket_sticker_512px_001_.webp",
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,178 +0,0 @@
|
||||
---
|
||||
title: "Send Template Message"
|
||||
sidebarTitle: "Template Message"
|
||||
description: "Post a template message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp template messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="template" type="string" required={true}>
|
||||
The name of the template you want to send. Note that these have to be approved by Meta before they can be used. You can find this in the your WhatsApp Business dashboard.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="languageCode" type="string" required={true}>
|
||||
The language code of the template you want to send, e.g. "en_US". You can find this in the your WhatsApp Business dashboard.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="parameters" type="object" required={false}>
|
||||
You can customise the message by providing values for variables in the template. There are three sections header, body and buttons. [Full WhatsApp documentation](https://developers.facebook.com/micro_site/url/?click_from_context_menu=true&country=GB&destination=https%3A%2F%2Fdevelopers.facebook.com%2Fdocs%2Fwhatsapp%2Fapi%2Fmessages%2Fmessage-templates%2F%23local&event_type=click&last_nav_impression_id=1gi9JORcnblgd3gKs&max_percent_page_viewed=52&max_viewport_height_px=1272&max_viewport_width_px=2560&orig_http_referrer=https%3A%2F%2Fdevelopers.facebook.com%2Fdocs%2Fwhatsapp%2Fapi%2Fmessages%2Fmessage-templates%2F&orig_request_uri=https%3A%2F%2Fdevelopers.facebook.com%2Fajax%2Fdocs%2Fnav%2F%3Fpath1%3Dwhatsapp%26path2%3Dapi%26path3%3Dmessages%26path4%3Dmessage-templates®ion=emea&scrolled=true&session_id=1p7ElKefs7QDpKC36&site=developers)
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendText } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send a templated message, with variables
|
||||
//in this example we have included are the possible variables (mostly commented out)
|
||||
const templateResponse = await sendTemplate("template-msg", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
//this template must be approved in your WhatsApp Business Account
|
||||
template: "hello_world",
|
||||
languageCode: "en_US",
|
||||
//you only need to include these if your template has variables
|
||||
parameters: {
|
||||
//only include this if your header has variables, they can be text, image, video or document
|
||||
header: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Matt",
|
||||
},
|
||||
// {
|
||||
// type: "image",
|
||||
// image: {
|
||||
// link: "https://app.trigger.dev/emails/logo.png",
|
||||
// caption: "This is a logo",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// type: "video",
|
||||
// video: {
|
||||
// link: "https://media.giphy.com/media/5i7umUqAOYYEw/giphy.mp4",
|
||||
// caption: "This is a fun video",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// type: "document",
|
||||
// video: {
|
||||
// link: "https://upload.wikimedia.org/wikipedia/commons/2/20/Re_example.pdf",
|
||||
// caption: "This is a document",
|
||||
// },
|
||||
// },
|
||||
],
|
||||
//only include this if the body of your message has variables. They can be text, currency, date_time
|
||||
body: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Matt",
|
||||
},
|
||||
// {
|
||||
// type: "currency",
|
||||
// currency: {
|
||||
// amount_1000: 1000,
|
||||
// code: "USD",
|
||||
// fallback_value: "1000 USD",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// type: "date_time",
|
||||
// date_time: {
|
||||
// fallback_value: "2021-01-01",
|
||||
// },
|
||||
// }
|
||||
],
|
||||
//only include this if the buttons of your message have variables. They can be quick_reply or call_to_action
|
||||
buttons: [
|
||||
{
|
||||
sub_type: "quick_reply",
|
||||
parameters: [
|
||||
{
|
||||
type: "payload",
|
||||
payload: "buy",
|
||||
},
|
||||
// {
|
||||
// type: "text",
|
||||
// text: "Buy now!",
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
sub_type: "call_to_action",
|
||||
parameters: [
|
||||
{
|
||||
type: "text",
|
||||
text: "Buy now!",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,96 +0,0 @@
|
||||
---
|
||||
title: "Send Text Message"
|
||||
sidebarTitle: "Text Message"
|
||||
description: "Post a text message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp text messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="text" type="string" required={true}>
|
||||
The text of the message to be sent.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={false}>
|
||||
Optionally, add the id of the message you want to reply to. It will appear as a reply in the WhatsApp chat.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendText } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an automatic reply to the message
|
||||
const textResponse = await sendText("text-msg", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
text: "Hello! This is a text sent automatically from https://www.trigger.dev",
|
||||
//this is optional – if set, the message will appear quoting the original message
|
||||
isReplyTo: event.message.id,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,99 +0,0 @@
|
||||
---
|
||||
title: "Send Video Message"
|
||||
sidebarTitle: "Video Message"
|
||||
description: "Post a video message to WhatsApp"
|
||||
---
|
||||
|
||||
Send WhatsApp video messages from your WhatsApp Business Account.
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique string. Please see the [Keys and Resumability](/guides/resumability)
|
||||
doc for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="message" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="fromId" type="string" required={false}>
|
||||
The id of the phone number you want to send the message from. You can find this in the your WhatsApp Business dashboard. Note, this is not the phone number.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="to" type="string" required={false}>
|
||||
The phone number you want to send the message to.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="url" type="string" required={true}>
|
||||
The url of the video to be sent.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="caption" type="string" required={false}>
|
||||
Optional caption that sits below the video
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isReplyTo" type="string" required={false}>
|
||||
Optionally, add the id of the message you want to reply to. It will appear as a reply in the WhatsApp chat.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
|
||||
## Response
|
||||
|
||||
<ResponseField name="contacts" type="object">
|
||||
The contact information of who received the message
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messages" type="object">
|
||||
An array of message ids that were sent
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="messaging_product" type="string">
|
||||
Always `whatsapp`
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### Notify Slack on New GitHub Star
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript Automated reply to WhatsApp messages
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events, sendVideo } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//send an automatic video reply to the message
|
||||
const videoResponse = await sendVideo("video", {
|
||||
fromId: event.metadata.phone_number_id,
|
||||
to: event.message.from,
|
||||
url: "https://media.giphy.com/media/5i7umUqAOYYEw/giphy.mp4",
|
||||
caption: "OMGGGG CATTTT",
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
```json Example response
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"input": "12345678901",
|
||||
"wa_id": "12345678901"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
{
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
}
|
||||
],
|
||||
"messaging_product": "whatsapp"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,106 +0,0 @@
|
||||
---
|
||||
title: "Message Event"
|
||||
sidebarTitle: "Message"
|
||||
description: "Trigger a workflow whenever a WhatsApp message is received in your WhatsApp Business Account"
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//your workflow code here
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Params
|
||||
|
||||
<ParamField path="accountId" type="string" required={true}>
|
||||
Your WhatsApp Business Account id
|
||||
</ParamField>
|
||||
|
||||
## Event
|
||||
|
||||
<ResponseField name="message" type="object" required={true}>
|
||||
The message object has the type of message (e.g. text, video, audio etc) and
|
||||
the message content.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="contacts" type="object" required={true}>
|
||||
The contact information of the sender.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="metadata" type="object" required={true}>
|
||||
Information about the account and phone number that received the message, i.e.
|
||||
your WhatsApp Business Account details.
|
||||
</ResponseField>
|
||||
|
||||
## Example Workflows
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```typescript post a message to your support Slack channel
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import { events } from "@trigger.dev/whatsapp";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: events.messageEvent({
|
||||
accountId: "<account_id>",
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
//get the user from your database, using the phone number
|
||||
const user = await db.getUser({ phoneNumber: event.message.from });
|
||||
|
||||
if (!user) {
|
||||
await ctx.logger.error(`No user to phone number ${event.message.from}`);
|
||||
return;
|
||||
}
|
||||
|
||||
//post a message to your support Slack channel
|
||||
await slack.postMessage({
|
||||
channel: "support",
|
||||
text: `Support message from ${user.name} (${user.email})\n${event.message.body}`,
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Example Event payload
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "message",
|
||||
"message": {
|
||||
"id": "wamid.ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
"from": "12345678901",
|
||||
"text": {
|
||||
"body": "The quick brown fox jumps over the lazy dog"
|
||||
},
|
||||
"type": "text",
|
||||
"timestamp": 1675257050000
|
||||
},
|
||||
"contacts": [
|
||||
{
|
||||
"wa_id": "12345678901",
|
||||
"profile": {
|
||||
"name": "Matt Aitken"
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"phone_number_id": "987654321012",
|
||||
"display_phone_number": "15550676999"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
title: "WhatsApp reference"
|
||||
sidebarTitle: "Reference"
|
||||
description: "Reference for the WhatsApp integration"
|
||||
---
|
||||
|
||||
Navigate through the following pages for the full reference for the WhatsApp integration.
|
||||
|
||||
Or [view the examples](/examples/whatsapp) of how to use the WhatsApp integration.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: "Authentication"
|
||||
sidebarTitle: "Authentication"
|
||||
description: "Authentication"
|
||||
---
|
||||
|
||||
Coming soon...
|
||||
@@ -1,224 +0,0 @@
|
||||
{
|
||||
"name": "Trigger.dev",
|
||||
"logo": {
|
||||
"dark": "/logo/light.png",
|
||||
"light": "/logo/light.png",
|
||||
"href": "https://app.trigger.dev"
|
||||
},
|
||||
"favicon": "/images/favicon.png",
|
||||
"colors": {
|
||||
"primary": "#0fd122",
|
||||
"light": "#41FF54",
|
||||
"dark": "#632CCC",
|
||||
"anchors": {
|
||||
"from": "#069613",
|
||||
"to": "#0fd122"
|
||||
}
|
||||
},
|
||||
"backgroundImage": "/images/docs-background.png",
|
||||
"modeToggle": {
|
||||
"default": "dark",
|
||||
"isHidden": true
|
||||
},
|
||||
"topbarLinks": [
|
||||
{
|
||||
"name": "Login",
|
||||
"url": "https://app.trigger.dev"
|
||||
},
|
||||
{
|
||||
"name": "Sign up",
|
||||
"url": "https://app.trigger.dev"
|
||||
}
|
||||
],
|
||||
"topbarCtaButton": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/triggerdotdev/trigger.dev"
|
||||
},
|
||||
"anchors": [
|
||||
{
|
||||
"name": "Community",
|
||||
"icon": "discord",
|
||||
"url": "https://discord.gg/nkqV9xBYWy"
|
||||
},
|
||||
{
|
||||
"name": "GitHub",
|
||||
"icon": "github",
|
||||
"url": "https://github.com/triggerdotdev/trigger.dev"
|
||||
}
|
||||
],
|
||||
"navigation": [
|
||||
{
|
||||
"group": "Getting Started",
|
||||
"pages": [
|
||||
"welcome",
|
||||
"getting-started",
|
||||
"get-help",
|
||||
"viewing-runs",
|
||||
"changelog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Example workflows",
|
||||
"pages": [
|
||||
"examples/examples",
|
||||
"examples/github",
|
||||
"examples/resend",
|
||||
"examples/shopify",
|
||||
"examples/slack",
|
||||
"examples/whatsapp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Triggers",
|
||||
"pages": [
|
||||
"triggers/webhooks",
|
||||
"triggers/custom-events",
|
||||
"triggers/scheduled"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Integrations",
|
||||
"pages": [
|
||||
{
|
||||
"group": "APIs",
|
||||
"pages": [
|
||||
{
|
||||
"group": "GitHub",
|
||||
"pages": [
|
||||
{
|
||||
"group": "Events",
|
||||
"pages": [
|
||||
"integrations/apis/github/events/issue-comments",
|
||||
"integrations/apis/github/events/issues",
|
||||
"integrations/apis/github/events/new-star",
|
||||
"integrations/apis/github/events/pull-request-comments",
|
||||
"integrations/apis/github/events/pull-request-reviews",
|
||||
"integrations/apis/github/events/pull-requests",
|
||||
"integrations/apis/github/events/push"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Slack",
|
||||
"pages": [
|
||||
"integrations/apis/slack/actions/post-message",
|
||||
"integrations/apis/slack/actions/post-message-response",
|
||||
"integrations/apis/slack/actions/add-reaction",
|
||||
"integrations/apis/slack/actions/open-view"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Resend.com",
|
||||
"pages": [
|
||||
"integrations/apis/resend/actions/send-email"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "WhatsApp",
|
||||
"pages": [
|
||||
"integrations/apis/whatsapp/index",
|
||||
{
|
||||
"group": "Events",
|
||||
"pages": [
|
||||
"integrations/apis/whatsapp/events/message"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Actions",
|
||||
"pages": [
|
||||
"integrations/apis/whatsapp/actions/text-message",
|
||||
"integrations/apis/whatsapp/actions/reaction-message",
|
||||
"integrations/apis/whatsapp/actions/audio-message",
|
||||
"integrations/apis/whatsapp/actions/video-message",
|
||||
"integrations/apis/whatsapp/actions/document-message",
|
||||
"integrations/apis/whatsapp/actions/sticker-message",
|
||||
"integrations/apis/whatsapp/actions/template-message",
|
||||
"integrations/apis/whatsapp/actions/location-message",
|
||||
"integrations/apis/whatsapp/actions/contacts-message"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"integrations/authentication"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Functions",
|
||||
"pages": [
|
||||
"functions/fetch",
|
||||
"functions/logging",
|
||||
"functions/delays",
|
||||
"functions/send-event",
|
||||
"functions/run-once",
|
||||
"functions/loops-conditionals-etc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Guides",
|
||||
"pages": [
|
||||
"guides/resumability",
|
||||
"guides/event-filters",
|
||||
"guides/zod",
|
||||
"guides/event-driven"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "SDK Reference",
|
||||
"pages": [
|
||||
"reference/trigger",
|
||||
"reference/custom-event",
|
||||
"reference/webhook-event",
|
||||
"reference/schedule-event",
|
||||
"reference/send-event"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "API Reference",
|
||||
"pages": [
|
||||
"api-reference/events/sendEvent"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Webhook Catalog",
|
||||
"pages": [
|
||||
{
|
||||
"group": "Slack",
|
||||
"pages": [
|
||||
"integrations/apis/slack/events/block-action-interaction",
|
||||
"integrations/apis/slack/events/view-submission-interaction"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "GitHub",
|
||||
"pages": [
|
||||
"integrations/apis/github/events/push",
|
||||
"integrations/apis/github/events/issues",
|
||||
"integrations/apis/github/events/issue-comments",
|
||||
"integrations/apis/github/events/pull-requests",
|
||||
"integrations/apis/github/events/pull-request-reviews",
|
||||
"integrations/apis/github/events/pull-request-comments",
|
||||
"integrations/apis/github/events/new-star"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"footerSocials": {
|
||||
"twitter": "https://twitter.com/triggerdotdev",
|
||||
"github": "https://github.com/triggerdotdev/trigger.dev",
|
||||
"discord": "https://discord.gg/nkqV9xBYWy"
|
||||
},
|
||||
"api": {
|
||||
"auth": {
|
||||
"method": "bearer"
|
||||
}
|
||||
},
|
||||
"analytics": {
|
||||
"posthog": {
|
||||
"apiKey": "phc_cU8Ow5tDcy9alp09yWYpad98CHafOsfsXK3HzLM6uy0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Trigger.dev API
|
||||
version: v0.2.3
|
||||
description: Please see https://docs.trigger.dev for more details.
|
||||
contact:
|
||||
name: Eric
|
||||
email: eric@trigger.dev
|
||||
url: https://trigger.dev
|
||||
termsOfService: https://trigger.dev/terms
|
||||
servers:
|
||||
- url: https://app.trigger.dev/api/v1
|
||||
description: Trigger.dev
|
||||
tags:
|
||||
- name: "events"
|
||||
description: "Send and manage custom events"
|
||||
externalDocs:
|
||||
description: "Trigger.dev Docs"
|
||||
url: "https://docs.trigger.dev"
|
||||
security:
|
||||
- apiKey: []
|
||||
paths:
|
||||
/events:
|
||||
post:
|
||||
summary: Send Custom Event
|
||||
description: Send a custom event to run your customEvent Triggers
|
||||
operationId: "sendEvent"
|
||||
tags:
|
||||
- events
|
||||
externalDocs:
|
||||
description: "API method documentation"
|
||||
url: "https://docs.trigger.dev/api/events/sendEvent"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/customEvent"
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/customEvent"
|
||||
"401":
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/error"
|
||||
"405":
|
||||
description: Method not allowed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/error"
|
||||
"422":
|
||||
description: Unprocessable Entity
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/error"
|
||||
components:
|
||||
schemas:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
customEvent:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- event
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: "A unique event identifier, can be used to deduplicate events. Use a sufficiently unique ID generator, such as UUIDv4"
|
||||
event:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required:
|
||||
- name
|
||||
- payload
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: user.created
|
||||
description: "The name of the event. This is the same value you'd use in your customEvent trigger code to listen for events"
|
||||
payload:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
description: "The JSON payload of the event"
|
||||
context:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
description: "An optional context object for the event. This can be used to pass additional information about the event, such as the user who triggered it. Note that this is not currently exposed to the workflow (coming soon)."
|
||||
timestamp:
|
||||
type: string
|
||||
format: "date-time"
|
||||
example: "2022-01-01T12:30:00Z"
|
||||
description: "An optional timestamp for the event. If not provided, one will be generated. Must be in ISO 8601 format (e.g. new Date().toISOString())"
|
||||
delay:
|
||||
type: object
|
||||
description: "An optional delay object for the event. This can be used to delay the event by a certain amount of time. "
|
||||
oneOf:
|
||||
- type: object
|
||||
properties:
|
||||
seconds:
|
||||
type: integer
|
||||
- type: object
|
||||
properties:
|
||||
minutes:
|
||||
type: integer
|
||||
- type: object
|
||||
properties:
|
||||
hours:
|
||||
type: integer
|
||||
- type: object
|
||||
properties:
|
||||
days:
|
||||
type: integer
|
||||
- type: object
|
||||
properties:
|
||||
until:
|
||||
type: string
|
||||
format: date-time
|
||||
securitySchemes:
|
||||
apiKey:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: Authorization
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "1.0.0",
|
||||
"description": "Trigger.dev documentation",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "mintlify dev --port 3050"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mintlify": "2.0.16"
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
title: "customEvent Trigger"
|
||||
sidebarTitle: "customEvent"
|
||||
description: "Trigger a workflow when a custom event is received."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { customEvent, Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "user-created-notify-slack",
|
||||
name: "User Created - Notify Slack",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({ id: z.string(), admin: z.boolean() }),
|
||||
filter: {
|
||||
admin: [false],
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
<ParamField path="name" type="string" required={true}>
|
||||
The name of the custom event to listen for.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="filter" type="object" required={false}>
|
||||
An event filter to apply to the custom event payload. See the [event filter
|
||||
documentation](/guides/event-filters) for more information.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="schema" type="Zod Schema" required={true}>
|
||||
A Zod schema to validate the webhook event payload against. See our [Zod
|
||||
guide](/guides/zod) for more information.
|
||||
</ParamField>
|
||||
@@ -1,68 +0,0 @@
|
||||
---
|
||||
title: "scheduleEvent Trigger"
|
||||
sidebarTitle: "scheduleEvent"
|
||||
description: "Run a workflow on a recurring schedule."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { scheduleEvent } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "usage",
|
||||
name: "usage",
|
||||
on: scheduleEvent({ rateof: { minutes: 10 } }),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
You must use one of the following options, but not both:
|
||||
|
||||
<ParamField path="rateOf" type="object" required={false}>
|
||||
The rate of the schedule. This can be a number of minutes, hours,
|
||||
or days. For example, `{ rateOf: { minutes: 10 } }` will run
|
||||
every 10 minutes.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="cron" type="string" required={false}>
|
||||
A cron expression to run the workflow on. For example, `0 0 * * *` will run
|
||||
the workflow every hour at the top of the hour. See
|
||||
[crontab.guru](https://crontab.guru/) for more information.
|
||||
</ParamField>
|
||||
|
||||
## Event Payload
|
||||
|
||||
<ResponseField name="scheduledTime" type="Date" required={true}>
|
||||
The time the event was scheduled to run.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="lastRunAt" type="Date" required={false}>
|
||||
The time the event last run. This will be `undefined` if the event has never run. Use this parameter to run window queries:
|
||||
|
||||
```ts
|
||||
import { scheduleEvent, Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "usage",
|
||||
name: "usage",
|
||||
on: scheduleEvent({ rateof: { minutes: 10 } }),
|
||||
run: async (event, ctx) => {
|
||||
const { lastRunAt, scheduledTime } = event;
|
||||
|
||||
const query = `SELECT * FROM users WHERE created_at < ${scheduledTime}`;
|
||||
|
||||
if (lastRunAt) {
|
||||
query += ` AND created_at > ${lastRunAt}`;
|
||||
}
|
||||
|
||||
const latestUsers = await db.query(query);
|
||||
|
||||
// ...
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</ResponseField>
|
||||
@@ -1,97 +0,0 @@
|
||||
---
|
||||
title: "sendEvent"
|
||||
sidebarTitle: "sendEvent"
|
||||
description: "Send a custom event to Trigger, from inside or outside of a workflow."
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "usage",
|
||||
name: "usage",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.any(),
|
||||
}),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.sendEvent("Sending context user.created event", {
|
||||
name: "user.created",
|
||||
payload: {
|
||||
id: "1234_abc",
|
||||
},
|
||||
});
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
You can also use `sendEvent` by importing it from `@trigger.dev/sdk`:
|
||||
|
||||
```ts
|
||||
import { sendEvent } from "@trigger.dev/sdk";
|
||||
|
||||
await sendEvent("Sending context user.created event", {
|
||||
name: "user.created",
|
||||
payload: {
|
||||
id: "1234_abc",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
If calling `sendEvent` from outside of a workflow run, it will make an HTTP
|
||||
API request to app.trigger.dev to send the event. Make sure you set the
|
||||
`TRIGGER_API_KEY` environment variable if you will be using it this way.
|
||||
</Note>
|
||||
|
||||
## Parameters
|
||||
|
||||
<ParamField path="key" type="string" required={true}>
|
||||
A unique key for the event in the context of a workflow run. Please see the
|
||||
[Keys and Resumability](/guides/resumability) guide for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="event" type="object" required={true}>
|
||||
<Expandable title="properties" defaultOpen={true}>
|
||||
<ParamField path="id" type="string" required={false}>
|
||||
An optional unique ID for the event. If not provided, one will be
|
||||
generated automatically (using `clid`). Set this field to perform event
|
||||
deduplication.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="name" type="string" required={true}>
|
||||
The name of the event. This is the name you set when creating the
|
||||
`customEvent` trigger.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="payload" type="json object" required={true}>
|
||||
The payload of the event.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="timestamp" type="ISO8601 string" required={false}>
|
||||
An optional timestamp for the event. If not provided, one will be generated. Must be in ISO 8601 format (e.g. `new Date().toISOString()`)
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="context" type="json object" required={false}>
|
||||
An optional context object for the event. This can be used to pass
|
||||
additional information about the event, such as the user who triggered
|
||||
it. Note that this is not currently exposed to the workflow (coming soon).
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="delay" type="object" required={false}>
|
||||
An optional delay object for the event. This can be used to delay the
|
||||
event by a certain amount of time. Use one of the following options:
|
||||
|
||||
- `{ seconds: number }` - delay the event by a certain number of seconds
|
||||
- `{ minutes: number }` - delay the event by a certain number of minutes
|
||||
- `{ hours: number }` - delay the event by a certain number of hours
|
||||
- `{ days: number }` - delay the event by a certain number of days
|
||||
- `{ until: Date }` - delay the event until a certain date
|
||||
|
||||
See the [Delaying Event Delivery](/functions/send-event#delaying-event-delivery) docs for more info.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
@@ -1,159 +0,0 @@
|
||||
---
|
||||
title: "Trigger"
|
||||
sidebarTitle: "Trigger"
|
||||
description: "The Trigger class let's you define a workflow that is triggered by a specific event."
|
||||
---
|
||||
|
||||
## Constructor
|
||||
|
||||
### Usage
|
||||
|
||||
```ts
|
||||
import { customEvent, Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
const trigger = new Trigger({
|
||||
id: "user-created-notify-slack",
|
||||
name: "User Created - Notify Slack",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({ id: z.string(), admin: z.boolean() }),
|
||||
filter: {
|
||||
admin: [false],
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
});
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
<ParamField path="id" type="string" required={true}>
|
||||
An identifier for this trigger. Must unique across your Trigger.dev
|
||||
organization.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="name" type="string" required={true}>
|
||||
A display name for this trigger.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="apiKey" type="string" required={false}>
|
||||
Your Trigger.dev API key. If not provided, the API key will be read from the
|
||||
`TRIGGER_API_KEY` environment variable.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="endpoint" type="string" required={false}>
|
||||
The URL of the Trigger.dev WebSocket server. If not provided, the endpoint
|
||||
will point to the production server.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="logLevel" type="string" required={false}>
|
||||
The log level for the Trigger. Defaults to `info`
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="triggerTTL" type="number" required={false}>
|
||||
The TTL for the trigger in seconds. If the delay between the event timestamp
|
||||
and the current time is greater than the TTL, the trigger will not be
|
||||
executed. Defaults to `3600` seconds, or 1 hour.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="run" type="function" required={true}>
|
||||
The function that will be executed when the trigger is fired. The function
|
||||
will be passed the event data and a context object.
|
||||
</ParamField>
|
||||
|
||||
### Context Object
|
||||
|
||||
<ParamField path="id" type="string">
|
||||
The identifier of the individual run of this trigger.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="environment" type="string">
|
||||
Either `development` or `live`, depending on the API Key used.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="apiKey" type="string">
|
||||
The API Key used to authenticate this trigger.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="organizationId" type="string">
|
||||
The identifier of the organization that owns this trigger.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="logger" type="object">
|
||||
The logger object for this trigger. See the [Logging](/functions/logging) page
|
||||
for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="isTest" type="boolean">
|
||||
Whether or not this trigger is being run as a test.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="sendEvent" type="function">
|
||||
A function that can be used to send an event to trigger.dev. See the [Sending
|
||||
Events](/functions/send-event) page for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="waitFor" type="function">
|
||||
A function that can be used to wait for a specific amount of time before
|
||||
continuing. See the [Delays](/functions/delays) page for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="waitUntil" type="function">
|
||||
A function that can be used to wait for a specific date/time before
|
||||
continuing. See the [Delays](/functions/delays) page for more info.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="fetch" type="function">
|
||||
A function that can be used to make HTTP requests. See the
|
||||
[fetch](/functions/fetch) page for more info.
|
||||
</ParamField>
|
||||
|
||||
## listen
|
||||
|
||||
The `listen` function will register the Trigger with Trigger.dev and start listening for events.
|
||||
|
||||
### Usage
|
||||
|
||||
```ts
|
||||
const trigger = new Trigger({
|
||||
id: "user-created-notify-slack",
|
||||
name: "User Created - Notify Slack",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({ id: z.string(), admin: z.boolean() }),
|
||||
filter: {
|
||||
admin: [false],
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
});
|
||||
|
||||
trigger.listen();
|
||||
```
|
||||
|
||||
You can split the creation of the trigger and the listening for events by calling `trigger.listen()` at a later time.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts triggers.ts
|
||||
export const userCreatedNotifySlack = new Trigger({
|
||||
id: "user-created-notify-slack",
|
||||
name: "User Created - Notify Slack",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({ id: z.string(), admin: z.boolean() }),
|
||||
filter: {
|
||||
admin: [false],
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
});
|
||||
```
|
||||
|
||||
```ts index.ts
|
||||
import { userCreatedNotifySlack } from "./triggers";
|
||||
|
||||
userCreatedNotifySlack.listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
title: "webhookEvent Trigger"
|
||||
sidebarTitle: "webhookEvent"
|
||||
description: "Trigger a workflow when a webhook event is received"
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { webhookEvent, Trigger } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "caldotcom-to-slack",
|
||||
name: "Cal.com To Slack",
|
||||
on: webhookEvent({
|
||||
service: "cal.com",
|
||||
eventName: "BOOKING_CREATED",
|
||||
filter: {
|
||||
triggerEvent: ["BOOKING_CREATED"],
|
||||
},
|
||||
schema: z.any(),
|
||||
verifyPayload: {
|
||||
enabled: true,
|
||||
header: "X-Cal-Signature-256",
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
<ParamField path="service" type="string" required={true}>
|
||||
The name of the service that will be sending the webhook event.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="name" type="string" required={true}>
|
||||
The name of the event that will be sent by the service.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="filter" type="object" required={false}>
|
||||
An event filter to apply to the webhook event. See the [event filter
|
||||
documentation](/guides/event-filters) for more information.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="schema" type="Zod Schema" required={true}>
|
||||
A Zod schema to validate the webhook event payload against. See our [Zod
|
||||
guide](/guides/zod) for more information.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="verifyPayload" type="object" required={false}>
|
||||
Verify the payload of the webhook event. Currently only supports sha256 HMAC
|
||||
signatures.
|
||||
<Expandable title="properties">
|
||||
<ParamField path="enabled" type="boolean" required={false}>
|
||||
Whether to verify the payload of the webhook event. Defaults to `false`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="header" type="string" required={false}>
|
||||
The name of the header that contains the signature to verify the payload
|
||||
against. e.g. `X-Webhook-Signature`.
|
||||
</ParamField>
|
||||
|
||||
</Expandable>
|
||||
</ParamField>
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: "Resources"
|
||||
description: "Learn more about how to build amazing documentation"
|
||||
---
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Development" icon="rectangle-terminal" href="https://mintlify.com/docs/development">
|
||||
Run on your computer to see changes locally
|
||||
</Card>
|
||||
<Card title="Global Settings" icon="sliders" href="https://mintlify.com/docs/settings/global">
|
||||
Customizing the theme, branding, and other global configurations
|
||||
</Card>
|
||||
<Card title="Page Titles and Metadata" icon="heading" href="https://mintlify.com/docs/settings/page">
|
||||
Setting the title and metadata for navigation and SEO
|
||||
</Card>
|
||||
<Card title="Writing Content" icon="pen-nib" href="https://mintlify.com/docs/components/overview">
|
||||
Introduction on how to add and edit content
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
Learn more about how to take your documentation to the next level
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Custom Domains" icon="browser" href="https://mintlify.com/docs/settings/custom-domain/subdomain">
|
||||
Get the documentation hosted at your custom domain
|
||||
</Card>
|
||||
<Card title="Advanced Components" icon="paintbrush-pencil" href="https://mintlify.com/docs/components/advanced/accordion">
|
||||
Advanced components built for specific communication mediums
|
||||
</Card>
|
||||
<Card title="API Components" icon="square-code" href="https://mintlify.com/docs/api-components/overview">
|
||||
Add an API playground into your documentation
|
||||
</Card>
|
||||
<Card title="Analytics" icon="chart-mixed" href="https://mintlify.com/docs/analytics/supported-integrations">
|
||||
Learn how users are interacting with your documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,27 +0,0 @@
|
||||
---
|
||||
title: "Roadmap"
|
||||
description: "Coming changes to trigger.dev"
|
||||
---
|
||||
|
||||
## Next up
|
||||
|
||||
Features and integrations we'll be working on next.
|
||||
|
||||
#### Integrations
|
||||
|
||||
- Airtable
|
||||
- Slack: add support for commands and triggering on message events. Add actions for channel and team management.
|
||||
- Stripe
|
||||
- Google Sheets
|
||||
- Twitter
|
||||
|
||||
#### Features
|
||||
|
||||
- Unified workflow run list. See all your runs across all your workflows in one place.
|
||||
- Live logs. See your workflow logs in real time.
|
||||
- Workflow presence. See if your workflow is connected and running.
|
||||
- Error alerts. Get notified when your workflow fails or doesn't start.
|
||||
|
||||
#### Platform
|
||||
|
||||
- More robust and resilient webhook handling. We're working on a new webhook ingest system that will ensure webhook requests are never missed.
|
||||
@@ -1,117 +0,0 @@
|
||||
---
|
||||
title: "Custom event triggers"
|
||||
sidebarTitle: "Custom events"
|
||||
description: "Custom event triggers allow you to run workflows from your own code (or your other workflows)"
|
||||
---
|
||||
|
||||
[Send an event](/functions/send-event) and any workflows that subscribe to that custom event will get triggered.
|
||||
|
||||
## Name and Schemas
|
||||
|
||||
### Name
|
||||
|
||||
Custom event triggers have a `name`. They will only get triggered when a custom event with that name are sent.
|
||||
|
||||
### Schema
|
||||
|
||||
Custom event triggers take a [Zod](https://github.com/colinhacks/zod) schema. This is used to validate the data that is sent with the event. If the data does not match the schema, the workflow will not run.
|
||||
|
||||
It also means that inside your run function the event param will be typed correctly. We use [Zod](https://github.com/colinhacks/zod#installation) for our schemas – it's a fantastic library that allows you to define schemas in a very simple way.
|
||||
|
||||
You can always start out by using `z.any()` as your schema, and then later on you can add more strict validation. See our [Zod guide](/guides/zod) for more information.
|
||||
|
||||
## Filters
|
||||
|
||||
You can also add filters to your custom event triggers. This allows you to filter out events that you don't want to run your workflow for.
|
||||
|
||||
```ts
|
||||
new Trigger({
|
||||
id: "new-user-slack",
|
||||
name: "New user slack message",
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
paidPlan: z.boolean(),
|
||||
}),
|
||||
filter: {
|
||||
//only run the workflow if the user is paying
|
||||
paidPlan: [true],
|
||||
},
|
||||
}),
|
||||
//this function is run when the custom event is received
|
||||
run: async (event, ctx) => {
|
||||
//send a message to the #new-users Slack channel with user details
|
||||
const response = await slack.postMessage("send-to-slack", {
|
||||
channel: "new-users",
|
||||
text: `New user: ${event.name} (${event.email}) signed up. ${
|
||||
event.paidPlan ? "They are paying" : "They are on the free plan"
|
||||
}.`,
|
||||
});
|
||||
|
||||
return response.message;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
Please see the [Event filters guide](/guides/event-filters) for more information.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
import { Trigger, customEvent } from "@trigger.dev/sdk";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
import { z } from "zod";
|
||||
|
||||
//this workflow will run when a "user.created" event is sent
|
||||
new Trigger({
|
||||
id: "new-user-slack",
|
||||
name: "New user slack message",
|
||||
apiKey: "<your_api_key>",
|
||||
//this is the custom event subscription
|
||||
on: customEvent({
|
||||
name: "user.created",
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
paidPlan: z.boolean(),
|
||||
}),
|
||||
}),
|
||||
//this function is run when the custom event is received
|
||||
run: async (event, ctx) => {
|
||||
//send a message to the #new-users Slack channel with user details
|
||||
const response = await slack.postMessage("send-to-slack", {
|
||||
channel: "new-users",
|
||||
text: `New user: ${event.name} (${event.email}) signed up. ${
|
||||
event.paidPlan ? "They are paying" : "They are on the free plan"
|
||||
}.`,
|
||||
});
|
||||
|
||||
return response.message;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
That workflow will never run, unless an event is sent from your code somewhere – it can be sent from a completely different server.
|
||||
|
||||
## Sending an event
|
||||
|
||||
There is a [full guide on sending events](/functions/send-event) but here is a quick example:
|
||||
|
||||
```ts
|
||||
import { sendEvent } from "@trigger.dev/sdk";
|
||||
|
||||
//send an event with the name "user.created"
|
||||
await sendEvent("fire-user-created-event", {
|
||||
name: "user.created",
|
||||
payload: { name: "John Doe", email: "john@doe.com", paidPlan: true },
|
||||
});
|
||||
```
|
||||
|
||||
If you are calling this from inside a workflow, ensure that the first parameter is unique inside your workflow.
|
||||
|
||||
<Note>
|
||||
The same event can trigger many different workflows, just subscribe to the
|
||||
same event name to achieve this.
|
||||
</Note>
|
||||
@@ -1,109 +0,0 @@
|
||||
---
|
||||
title: "Scheduled triggers"
|
||||
sidebarTitle: "Scheduled"
|
||||
description: "Run a workflow on a recurring schedule"
|
||||
---
|
||||
|
||||
See the [reference](/reference/schedule-event) for more details.
|
||||
|
||||
## Examples
|
||||
|
||||
### Every 5 minutes
|
||||
|
||||
This job will run every 5 minutes, starting 5 minutes after this code is first run on your server (that includes running locally).
|
||||
|
||||
```ts
|
||||
import { Trigger, scheduleEvent } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "scheduled-workflow",
|
||||
name: "Scheduled Workflow",
|
||||
apiKey: "<your_api_key>",
|
||||
on: scheduleEvent({ rateOf: { minutes: 5 } }),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("Received the scheduled event", {
|
||||
event,
|
||||
wallTime: new Date(),
|
||||
});
|
||||
|
||||
return { foo: "bar" };
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
### Using CRON syntax
|
||||
|
||||
This job will run at 2:30pm every Monday. You can get help with [CRON syntax](https://crontab.guru/).
|
||||
|
||||
```ts
|
||||
import { Trigger, scheduleEvent } from "@trigger.dev/sdk";
|
||||
|
||||
new Trigger({
|
||||
id: "cron-scheduled-workflow",
|
||||
name: "Cron Scheduled Workflow",
|
||||
apiKey: "<your_api_key>",
|
||||
on: scheduleEvent({ cron: "30 14 * * 1" }),
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("Received the cron scheduled event", {
|
||||
event,
|
||||
wallTime: new Date(),
|
||||
});
|
||||
|
||||
return { foo: "bar" };
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
## Preventing late runs
|
||||
|
||||
To prevent a scheduled trigger from running late, you can set a `triggerTTL` option when creating the `Trigger`, like so:
|
||||
|
||||
```ts
|
||||
new Trigger({
|
||||
id: "scheduled-workflow",
|
||||
name: "Scheduled Workflow",
|
||||
apiKey: "<your_api_key>",
|
||||
on: scheduleEvent({ rateOf: { minutes: 5 } }),
|
||||
triggerTTL: 300,
|
||||
run: async (event, ctx) => {
|
||||
await ctx.logger.info("Received the scheduled event", {
|
||||
event,
|
||||
wallTime: new Date(),
|
||||
});
|
||||
|
||||
return { foo: "bar" };
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
This will prevent the trigger from running if it is running more than `300` seconds behind, which can happen if the server running your `Trigger` code goes down or is otherwise unavailable.
|
||||
|
||||
This is especially useful for scheduled triggers that run on a very short interval, like every minute, so you don't get a backlog of runs that all run at once when the server comes back online.
|
||||
|
||||
<Tip>
|
||||
Set your `triggerTTL` to the same time (or double) as the rateOf the trigger.
|
||||
</Tip>
|
||||
|
||||
## Live-only scheduled events
|
||||
|
||||
In many cases, you only want scheduled events to run when your code is running on a server, and not locally during development. To do this, you can check the `context.environment` property together with the `context.isTest` property, like so:
|
||||
|
||||
```ts
|
||||
new Trigger({
|
||||
id: "check-scheduler",
|
||||
name: "Check Scheduler",
|
||||
on: scheduleEvent({ rateOf: { minutes: 10 } }),
|
||||
logLevel: "info",
|
||||
triggerTTL: 600,
|
||||
run: async (event, context) => {
|
||||
// Return if in development and not running a test
|
||||
if (context.environment === "development" && !context.isTest) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do stuff here
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
By checking `context.isTest`, you can manually test scheduled events locally before pushing to live.
|
||||
@@ -1,120 +0,0 @@
|
||||
---
|
||||
title: "Webhooks"
|
||||
sidebarTitle: "Webhooks"
|
||||
description: "Webhooks allow you to subscribe to events from APIs you use."
|
||||
---
|
||||
|
||||
Webhooks are a crucial part of API development, allowing for real-time reactions to various events across different systems, such as when a Stripe Payment is made, or when a GitHub issue is created.
|
||||
|
||||
## Advantages of using Trigger.dev for webhooks
|
||||
|
||||
Webhooks can be difficult to work with, especially when developing locally. We make them far easier to use with our [integrations](/integrations/apis).
|
||||
|
||||
- You don't need to register/unregister for webhooks, we do it for you
|
||||
- They work locally during development without needing to use tunnels (e.g. Ngrok)
|
||||
- We receive the webhook, then keep trying to send it to you until you receive it. If your server goes down, no problem.
|
||||
|
||||
## Usage
|
||||
|
||||
There are two ways to use webhooks with Trigger.dev:
|
||||
|
||||
1. Use one of our built-in integrations, such as [GitHub](/integrations/github). We'll take care of registering the webhook for you.
|
||||
2. Use our [webhookEvent](/reference/webhook-event) function to create a webhook subscription and you'll register the webhook yourself.
|
||||
|
||||
## Webhook integrations
|
||||
|
||||
We currently have built in integrations for the following webhooks:
|
||||
|
||||
- [GitHub](/integrations/apis/github)
|
||||
|
||||
Please [join our discord community](https://discord.gg/kA47vcd8P6) and let us know which integration you'd like us to add.
|
||||
|
||||
We've documented all the support webhooks for each integration in the sidebar, for example the GitHub [newStarEvent](/integrations/apis/github/events/new-star) webhook:
|
||||
|
||||
```ts
|
||||
import * as github from "@trigger.dev/github";
|
||||
|
||||
new Trigger({
|
||||
id: "demo",
|
||||
on: github.events.newStarEvent({
|
||||
repo: "triggerdotdev/trigger.dev",
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
Once you've connected to Trigger.dev, and authorized your GitHub account, we'll go ahead and register the webhook in the repository you've specified and start triggering your `Trigger.run` function when new stars roll in.
|
||||
|
||||
## Manual Webhooks
|
||||
|
||||
If we haven't built out the integration you need, you can use our `webhookEvent` function to create a webhook subscription. You'll need to register the webhook yourself, but we'll take care of the rest. Here's an example for triggering events when a new booking happens in [Cal.com](https://cal.com):
|
||||
|
||||
```ts
|
||||
import { Trigger, webhookEvent } from "@trigger.dev/sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
new Trigger({
|
||||
id: "caldotcom-to-slack",
|
||||
name: "Cal.com To Slack",
|
||||
on: webhookEvent({
|
||||
service: "cal.com",
|
||||
eventName: "BOOKING_CREATED",
|
||||
filter: {
|
||||
triggerEvent: ["BOOKING_CREATED"],
|
||||
},
|
||||
schema: z.any(),
|
||||
verifyPayload: {
|
||||
enabled: true,
|
||||
header: "X-Cal-Signature-256",
|
||||
},
|
||||
}),
|
||||
run: async (event, ctx) => {},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
For more information on the various options for `webhookEvent`, see the [webhookEvent reference](/reference/webhook-event).
|
||||
|
||||
Once you connect to Trigger.dev, we will display the URL and (optionally) the secret you need to register with the webhook provider on the workflow overview page:
|
||||
|
||||

|
||||
|
||||
Copy the URL and secret, and register the webhook with the provider (in this case, Cal.com). Once you've done that, we'll start triggering your `Trigger.run` function when the webhook fires.
|
||||
|
||||
## Examples
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```ts Github
|
||||
import { Trigger } from "@trigger.dev/sdk";
|
||||
import * as github from "@trigger.dev/github";
|
||||
import * as slack from "@trigger.dev/slack";
|
||||
|
||||
new Trigger({
|
||||
id: "escalate-critical-issues",
|
||||
name: "Posts to Slack when GitHub Issue created or modified",
|
||||
apiKey: "<my_api_key>",
|
||||
//this is the webhook subscription
|
||||
on: github.events.issueEvent({
|
||||
repo: "my-github-org/my-github-repo",
|
||||
}),
|
||||
//this function is run when the webhook fires
|
||||
run: async (event, ctx) => {
|
||||
if (event.action === "labeled") {
|
||||
await ctx.logger.info(
|
||||
`The issue ${event.issue.title} was labeled ${event.label.name}`
|
||||
);
|
||||
|
||||
if (event.label.name === "critical") {
|
||||
await slack.postMessage("send-to-slack", {
|
||||
channel: "serious-issues",
|
||||
text: `Critical issue: ${event.issue.title} was labeled ${event.label.name}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
},
|
||||
}).listen();
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
title: "Viewing runs"
|
||||
sidebarTitle: "Viewing runs"
|
||||
description: "Full visibility of every run your workflow has made."
|
||||
---
|
||||
|
||||
One of the most powerful features of Trigger.dev is the runs page. All of the steps in a workflow, including the initial event, can be viewed in detail. See the status / output of each step, the logs, rich previews, errors and much more.
|
||||
|
||||

|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
title: "Trigger.dev Documentation"
|
||||
sidebarTitle: "Welcome"
|
||||
description: ""
|
||||
---
|
||||
|
||||
Trigger.dev is an open source platform that makes it easy for developers to create event-driven background tasks directly in their code. Build, test and run workflows locally using our SDK. Subscribe to webhooks, schedule jobs, run background jobs and add long delays easily and reliably. In our web app you get full visibility of every run your workflow has ever made.
|
||||
|
||||
|
||||
<CardGroup>
|
||||
<Card title="Getting Started" icon="circle-play" href="/getting-started">
|
||||
Quickly get up and running with Trigger.dev by following our quick start
|
||||
guide.
|
||||
</Card>
|
||||
<Card
|
||||
title="Examples"
|
||||
icon="arrow-right-arrow-left"
|
||||
href="/examples/examples"
|
||||
>
|
||||
One of the quickest ways to learn how Trigger.dev works is to view some
|
||||
example workflows.
|
||||
</Card>
|
||||
<Card
|
||||
title="Join Our Discord"
|
||||
icon="discord"
|
||||
href="https://discord.gg/kA47vcd8P6"
|
||||
>
|
||||
The #help-and-questions channel is a great place to get help with any
|
||||
questions about Trigger.dev.
|
||||
</Card>
|
||||
<Card
|
||||
title="Schedule a call"
|
||||
icon="phone"
|
||||
href="https://cal.com/team/triggerdotdev/support"
|
||||
>
|
||||
Arrange a call with one of the founders. We can help answer questions, build
|
||||
API integrations for you and help you with workflows.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
|
||||
Workflows live in your codebase so you can use your existing types, functions, version control and IDE. They are triggered by us but run on your server so your private data is never exposed.
|
||||
|
||||
|
||||
_A workflow in action:_
|
||||

|
||||
|
||||
<iframe
|
||||
width="100%"
|
||||
height="440"
|
||||
src="https://www.youtube.com/embed/aFlwD0frvnQ?rel=0"
|
||||
title="YouTube video player"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"sourceType": "unambiguous",
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"chrome": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"@babel/preset-typescript",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
|
||||
SESSION_SECRET=<random string>
|
||||
MAGIC_LINK_SECRET=<random string>
|
||||
GITHUB_CLIENT_ID=<random string>
|
||||
GITHUB_SECRET=<random string>
|
||||
FROM_EMAIL=<your email address>
|
||||
REPLY_TO_EMAIL=<your email address>
|
||||
RESEND_API_KEY=<RESEND_API_KEY>
|
||||
MERGENT_KEY=<Mergent key>
|
||||
LOGIN_ORIGIN=http://localhost:3000
|
||||
APP_ORIGIN=http://localhost:3000
|
||||
|
||||
# Production Pulsar
|
||||
# PULSAR_SERVICE_URL="pulsar+ssl://<cluster>.<orgId>.snio.cloud:6651"
|
||||
# PULSAR_CLIENT_ID="<client id>"
|
||||
# PULSAR_CLIENT_SECRET="<client secret>"
|
||||
# PULSAR_ISSUER_URL="https://auth.streamnative.cloud/"
|
||||
# PULSAR_AUDIENCE="urn:sn:pulsar:<orgId>:<instanceName>"
|
||||
# PULSAR_TENANT="triggerdotdev"
|
||||
# PULSAR_WORKFLOWS_NAMESPACE="workflows"
|
||||
# PULSAR_QUEUES_NAMESPACE="queues"
|
||||
|
||||
# Dev Pulsar
|
||||
PULSAR_SERVICE_URL="pulsar://localhost:6650"
|
||||