<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: tomas</title>
    <description>The latest articles on DEV Community by tomas (@tomas).</description>
    <link>https://dev.to/tomas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F164683%2F197538f4-3c9e-48e1-8edc-548fca058f51.png</url>
      <title>DEV Community: tomas</title>
      <link>https://dev.to/tomas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tomas"/>
    <language>en</language>
    <item>
      <title>✉ Publish a Newsletter Directly from GitHub</title>
      <dc:creator>tomas</dc:creator>
      <pubDate>Fri, 18 Sep 2020 06:51:39 +0000</pubDate>
      <link>https://dev.to/tomas/publish-a-newsletter-directly-from-github-4m8b</link>
      <guid>https://dev.to/tomas/publish-a-newsletter-directly-from-github-4m8b</guid>
      <description>&lt;h6&gt;
  
  
  &lt;center&gt;Photo by &lt;a href="https://unsplash.com/@engine9?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Andrey  Larin&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/paper-plane?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/center&gt;
&lt;/h6&gt;

&lt;p&gt;Hey there 👋&lt;/p&gt;

&lt;p&gt;For this Hackathon, my inspiration was GitHub's Release Radar, a place where I discovered a lot of interesting projects. I'm glad that it's back and I think it's an excellent resource for the community so I wanted to replicate that.&lt;/p&gt;

&lt;p&gt;Using GitHub as a platform for this enables all of Git's features like version control, and more importantly, collaboration so anyone can curate what goes inside the newsletter through a Pull Request.&lt;/p&gt;

&lt;p&gt;The GitHub Action uses SendGrid to send emails and keep track of all the subscribers and it's easily adaptable to launch your own newsletter!&lt;/p&gt;

&lt;p&gt;Just create a repo, edit the README and follow the instructions:&lt;/p&gt;

&lt;h3&gt;
  
  
  My Workflow
&lt;/h3&gt;

&lt;h1&gt;
  
  
  Set up
&lt;/h1&gt;

&lt;p&gt;You will need a SendGrid account and have completed these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sendgrid.com/docs/ui/account-and-settings/how-to-set-up-domain-authentication/" rel="noopener noreferrer"&gt;Set Up Domain Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://app.sendgrid.com/settings/api_keys" rel="noopener noreferrer"&gt;Create Full Access API Key&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the generated API Key as a secret named &lt;code&gt;SENDGRID_API_KEY&lt;/code&gt; in your repo settings.&lt;/p&gt;

&lt;p&gt;It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfgg2dem1unh1s2rqbsj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfgg2dem1unh1s2rqbsj.png" alt="github com_KNawm_release-radar_settings_secrets" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mc.sendgrid.com/forms/signup" rel="noopener noreferrer"&gt;Create Signup Forms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you create it, go to &lt;a href="https://mc.sendgrid.com/contacts" rel="noopener noreferrer"&gt;Contacts&lt;/a&gt; and open the list that was created automatically, to view it's ID open the list and check the URL, the ID will look like this: &lt;code&gt;81f44a3f-f1c2-4f47-a9a9-df79dd32d246&lt;/code&gt;. This will be your &lt;code&gt;list_id&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mc.sendgrid.com/unsubscribe-groups" rel="noopener noreferrer"&gt;Create Unsubscribe Group&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you create it, you will be able to see it's ID, it will look like this: &lt;code&gt;22584&lt;/code&gt;. This will be your &lt;code&gt;suppression_group_id&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mc.sendgrid.com/senders/new" rel="noopener noreferrer"&gt;Add a Sender&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you create it, click the 3 dots in the right of the Sender Management page and Edit the entry, check the URL and you will find a number that looks like this: &lt;code&gt;1057550&lt;/code&gt;. This will be your &lt;code&gt;sender_id&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inputs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;All inputs are REQUIRED&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;subject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The subject line of the newsletter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The recipient List ID that will receive the newsletter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suppression_group_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The ID of the Suppression Group to allow recipients to unsubscribe.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sender_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The ID of the verified Sender.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Example usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Newsletter&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Subject'&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;newsletter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Send newsletter&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Send newsletter&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;KNawm/newsletter-action@v1&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SENDGRID_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SENDGRID_API_KEY }}&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.inputs.subject }}&lt;/span&gt;
        &lt;span class="na"&gt;list_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;81f44a3f-f1c2-4f47-a9a9-df79dd32d246'&lt;/span&gt;
        &lt;span class="na"&gt;suppression_group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22584&lt;/span&gt;
        &lt;span class="na"&gt;sender_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1057550&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Demo: &lt;a href="https://github.com/KNawm/release-radar" rel="noopener noreferrer"&gt;KNawm/release-radar&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to trigger the workflow manually going to the Actions page of your repo and provide a subject line.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnldlkg331gtahnglja7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnldlkg331gtahnglja7m.png" width="640" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once it's triggered it will send the content of your README to your list of recipients after 5 minutes.&lt;/p&gt;

&lt;p&gt;If it's working you can enter &lt;a href="https://mc.sendgrid.com/single-sends" rel="noopener noreferrer"&gt;here&lt;/a&gt; and you should see your email scheduled:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldtb1ljt78kxcgha2lbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldtb1ljt78kxcgha2lbg.png" width="800" height="149"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Wacky Wildcards&lt;/p&gt;
&lt;h3&gt;
  
  
  Link to Code and Demo
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/KNawm" rel="noopener noreferrer"&gt;
        KNawm
      &lt;/a&gt; / &lt;a href="https://github.com/KNawm/newsletter-action" rel="noopener noreferrer"&gt;
        newsletter-action
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      📩 A GitHub Action for sending email formatted using Markdown.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  &lt;code&gt;newsletter-action&lt;/code&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;
  A GitHub Action for sending email formatted using Markdown
&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;
     
    &lt;a href="https://github.com/KNawm/newsletter-action./LICENSE" rel="noopener noreferrer"&gt;
        &lt;img src="https://camo.githubusercontent.com/0be5216e615b0012976fe492b15568b44b45912356476457ea1ef80d2a384051/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e7376673f7374796c653d666f722d7468652d6261646765" title="License"&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Set up&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;You will need a SendGrid account and have completed these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sendgrid.com/docs/ui/account-and-settings/how-to-set-up-domain-authentication/" rel="nofollow noopener noreferrer"&gt;Set Up Domain Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://app.sendgrid.com/settings/api_keys" rel="nofollow noopener noreferrer"&gt;Create Full Access API Key&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the generated API Key as a secret named &lt;code&gt;SENDGRID_API_KEY&lt;/code&gt; in your repo settings.&lt;/p&gt;

&lt;p&gt;It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/7613080/93562875-3bdf8300-f95d-11ea-869b-7dba1ef83f21.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F7613080%2F93562875-3bdf8300-f95d-11ea-869b-7dba1ef83f21.png" alt="github com_KNawm_release-radar_settings_secrets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mc.sendgrid.com/forms/signup" rel="nofollow noopener noreferrer"&gt;Create Signup Forms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you create it, go to &lt;a href="https://mc.sendgrid.com/contacts" rel="nofollow noopener noreferrer"&gt;Contacts&lt;/a&gt; and open the list that was created automatically, to view it's ID open the list and check the URL, the ID will look like this: &lt;code&gt;81f44a3f-f1c2-4f47-a9a9-df79dd32d246&lt;/code&gt;. This will be your &lt;code&gt;list_id&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mc.sendgrid.com/unsubscribe-groups" rel="nofollow noopener noreferrer"&gt;Create Unsubscribe Group&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you create it, you will be able to see it's ID, it will look like this: &lt;code&gt;22584&lt;/code&gt;. This will be your &lt;code&gt;suppression_group_id&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mc.sendgrid.com/senders/new" rel="nofollow noopener noreferrer"&gt;Add a Sender&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you create it, click the 3 dots in the right of the Sender Management page and Edit the entry, check the URL and you…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/KNawm/newsletter-action" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/KNawm" rel="noopener noreferrer"&gt;
        KNawm
      &lt;/a&gt; / &lt;a href="https://github.com/KNawm/release-radar" rel="noopener noreferrer"&gt;
        release-radar
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ✉ Welcome to Release Radar Community, where we share projects curated and shipped by you, from world-changing technologies to weekend side projects.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h6 class="heading-element"&gt;
  &lt;code&gt;Issue #1&lt;/code&gt;
&lt;/h6&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  &lt;code&gt;Release Radar Community&lt;/code&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;
  Welcome to Release Radar Community, where we share projects curated and shipped by you, from world-changing technologies to weekend side projects
&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;
    &lt;a href="https://cdn.forms-content.sg-form.com/e6210827-f8dd-11ea-8417-562ccc34fb80" rel="nofollow noopener noreferrer"&gt;
        &lt;img src="https://camo.githubusercontent.com/281df9b32e7b6473bbc493e85ff143fdcab8a3d0645c5c5693ad5f50fb5ea2fc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d6f6e74686c792d537562736372696265253230746f2532307468652532306e6577736c65747465722d7265643f7374796c653d666f722d7468652d6261646765266c6f676f3d646174613a696d6167652f706e673b6261736536342c6956424f5277304b47676f414141414e5355684555674141414351414141416b4341594141414468414a69594141414139456c45515652344165325549517943554242414355534466515a374d74714c775769774a345052594c535061444161445553446651596a7754364366515169415639776a46303451654132743376624377426a442f37784130736378796e4c4d735144506e466f72726a384672524261375a6155494c574a4670516e51316d3244637658474e466f3644503851526a37494d436a7a674f6f4857514f4c2f45744d75793444796f2b434549546a697558527468684155324a6363646872586e545044534b6b6973393072634d384e48773939364b726155725a784c50616a377778752b5250636737665048636d6a315a65347253422f51426337314832476f49506b3142484b724d416d5338364c4d6c566d5135436148316a354978344d387949502b4a696848612b356130426d74575774424939786a616843535959526859496a6a4f473871416e4a6f576b65444e4141414141424a52553545726b4a6767673d3d" title="Subscribe to the newsletter"&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;GitHub CLI 1.0&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;GitHub CLI brings GitHub to your terminal. It reduces context switching, helps you focus, and enables you to more easily script and create your own workflows.
With GitHub CLI 1.0, you can:&lt;/p&gt;
&lt;p&gt;Run your entire GitHub workflow from the terminal, from issues through releases
Call the GitHub API to script nearly any action, and set a custom alias for any command
Connect to GitHub Enterprise Server in addition to GitHub.com&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/ac26f79478250a755b0d1c39c8796030a689e971ae10791bed7376ff3722e076/68747470733a2f2f6769746875622e626c6f672f77702d636f6e74656e742f75706c6f6164732f323032302f30392f476974487562434c495f536f6369616c436172645f56657273696f6e4e756d6265725f4e6f5375624c696e655f76322e706e673f773d31323030"&gt;&lt;img src="https://camo.githubusercontent.com/ac26f79478250a755b0d1c39c8796030a689e971ae10791bed7376ff3722e076/68747470733a2f2f6769746875622e626c6f672f77702d636f6e74656e742f75706c6f6164732f323032302f30392f476974487562434c495f536f6369616c436172645f56657273696f6e4e756d6265725f4e6f5375624c696e655f76322e706e673f773d31323030" alt="GitHub CLI 1.0"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;npm CLI v7.0.0&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;npm 7 comes with some long-awaited and requested features including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Workspaces: a set of features to the npm CLI that provide support to managing multiple packages from within a singular top-level, root package&lt;/li&gt;
&lt;li&gt;Automatically installing peer dependencies: prior to npm 7 developers needed to manage and install their…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/KNawm/release-radar" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>actionshackathon</category>
      <category>showdev</category>
      <category>github</category>
      <category>sendgrid</category>
    </item>
    <item>
      <title>Monetize your Dart apps with Web Monetization</title>
      <dc:creator>tomas</dc:creator>
      <pubDate>Sat, 06 Jun 2020 03:02:48 +0000</pubDate>
      <link>https://dev.to/tomas/monetize-your-dart-apps-with-web-monetization-5h3g</link>
      <guid>https://dev.to/tomas/monetize-your-dart-apps-with-web-monetization-5h3g</guid>
      <description>&lt;h6&gt;
  
  
  Dart and the related logo are trademarks of Google LLC. I am not endorsed by or affiliated with Google LLC.
&lt;/h6&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Monetization&lt;/code&gt; is a Dart package for implementing and controlling Web Monetization on your web app. It exposes a straightforward API that resembles and extends the functionality of the Web Monetization's JavaScript API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category: Foundational Technology
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tomasarias.me/monetization" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/KNawm/monetization/tree/master/example" rel="noopener noreferrer"&gt;Demo code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/KNawm" rel="noopener noreferrer"&gt;
        KNawm
      &lt;/a&gt; / &lt;a href="https://github.com/KNawm/monetization" rel="noopener noreferrer"&gt;
        monetization
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      💸 A wrapper around the Web Monetization API to monetize apps.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
  &lt;code&gt;monetization&lt;/code&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;
  A wrapper around the &lt;a href="https://webmonetization.org/" rel="nofollow noopener noreferrer"&gt;Web Monetization API&lt;/a&gt;
&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;
    &lt;a href="https://pub.dev/packages/monetization" rel="nofollow noopener noreferrer"&gt;
        &lt;img src="https://camo.githubusercontent.com/a22704386b6c8e9a28efefa3009301438dd7e78f7ebc9b6c60577a0d9ae964d5/68747470733a2f2f696d672e736869656c64732e696f2f7075622f762f6d6f6e6574697a6174696f6e3f7374796c653d666f722d7468652d6261646765" title="Pub Version"&gt;
    &lt;/a&gt;
     
    &lt;a href="https://github.com/KNawm/monetization./LICENSE" rel="noopener noreferrer"&gt;
        &lt;img src="https://camo.githubusercontent.com/0be5216e615b0012976fe492b15568b44b45912356476457ea1ef80d2a384051/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e7376673f7374796c653d666f722d7468652d6261646765" title="License"&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Offer extra content and features for users who stream micro-payments — including premium features, additional content, or digital goods.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;
  &lt;a href="https://pub.dev/documentation/monetization/latest/monetization/Monetization-class.html" rel="nofollow noopener noreferrer"&gt;API Reference&lt;/a&gt;
&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;A simple usage example that initializes the monetization to a specific payment pointer:&lt;/p&gt;

&lt;div class="highlight highlight-source-dart notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s"&gt;'package:monetization/monetization.dart'&lt;/span&gt;;

&lt;span class="pl-en"&gt;main&lt;/span&gt;() {
  &lt;span class="pl-k"&gt;var&lt;/span&gt; monetization &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;Monetization&lt;/span&gt;(&lt;span class="pl-s"&gt;'&lt;span class="pl-cce"&gt;\$&lt;/span&gt;pay.tomasarias.me'&lt;/span&gt;);
}&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You can subscribe to Web Monetization events using a &lt;code&gt;Stream&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-dart notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;monetization.onPending.&lt;span class="pl-en"&gt;listen&lt;/span&gt;((event) {
  &lt;span class="pl-c"&gt;// Prepare to serve the monetized content&lt;/span&gt;
});

monetization.onStart.&lt;span class="pl-en"&gt;listen&lt;/span&gt;((event) {
  &lt;span class="pl-c"&gt;// Show monetized content&lt;/span&gt;
});

monetization.onProgress.&lt;span class="pl-en"&gt;listen&lt;/span&gt;((event) {
  &lt;span class="pl-c"&gt;// Do something on each micro-payment&lt;/span&gt;
});

monetization.onStop.&lt;span class="pl-en"&gt;listen&lt;/span&gt;((event) {
  &lt;span class="pl-c"&gt;// Hide monetized content&lt;/span&gt;
});&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You can also check if a user is paying without subscribing to the streams:&lt;/p&gt;
&lt;div class="highlight highlight-source-dart notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;Future&lt;/span&gt;&amp;lt;&lt;span class="pl-c1"&gt;bool&lt;/span&gt;&amp;gt; &lt;span class="pl-en"&gt;isPaying&lt;/span&gt;() &lt;span class="pl-k"&gt;async&lt;/span&gt; {
  &lt;span class="pl-c"&gt;// Prefer custom logic over this&lt;/span&gt;
  &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-c1"&gt;Future&lt;/span&gt;.&lt;span class="pl-en"&gt;delayed&lt;/span&gt;(&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;Duration&lt;/span&gt;(seconds&lt;span class="pl-k"&gt;:&lt;/span&gt; &lt;span class="pl-c1"&gt;3&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/KNawm/monetization" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;p&gt;For this project, I spent most of the time researching Web Monetization and it's eco-system, analyzing its strengths and where it lacked most.&lt;br&gt;
The provided JavaScript API was the first stop as it's the fundamental part to implement Web Monetization, I wanted to have all of the core functionality as familiar as possible. With this in mind, I began to implement the shared API between the two:&lt;/p&gt;

&lt;p&gt;In JavaScript, you can check if a user supports Web Monetization checking if &lt;code&gt;document.monetization === undefined&lt;/code&gt; but because in Dart there is no use in exposing the &lt;code&gt;document.monetization&lt;/code&gt; object directly, we can check everything using the &lt;code&gt;state&lt;/code&gt; getter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Returns the monetization state provided by the browser.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// **`undefined`**:&lt;/span&gt;
&lt;span class="c1"&gt;/// Monetization is not supported for this user.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// **`pending`**:&lt;/span&gt;
&lt;span class="c1"&gt;/// Streaming has been initiated, yet first non zero packet is&lt;/span&gt;
&lt;span class="c1"&gt;/// "pending". It will normally transition from this `state` to `started`,&lt;/span&gt;
&lt;span class="c1"&gt;/// yet not always.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// **`started`**:&lt;/span&gt;
&lt;span class="c1"&gt;/// Streaming has received a non zero packet and is still active.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// **`stopped`**:&lt;/span&gt;
&lt;span class="c1"&gt;/// Streaming is inactive. This could mean a variety of things:&lt;/span&gt;
&lt;span class="c1"&gt;/// - May not have started yet&lt;/span&gt;
&lt;span class="c1"&gt;/// - May be paused (potentially will be resumed)&lt;/span&gt;
&lt;span class="c1"&gt;/// - Has finished completely (and awaits another request)&lt;/span&gt;
&lt;span class="c1"&gt;/// - The payment request was denied by user intervention&lt;/span&gt;
&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_state&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;'undefined'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In JavaScript, you can listen to the &lt;code&gt;monetizationpending | monetizationstart | monetizationstop | monetizationprogress&lt;/code&gt; events, in Dart there are corresponding streams of those events that you can subscribe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Stream that tracks 'monetizationpending' events.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// This event fires when Web Monetization is enabled.&lt;/span&gt;
&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onPending&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// Stream that tracks 'monetizationstart' events.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// This event fires when Web Monetization has started actively paying.&lt;/span&gt;
&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// Stream that tracks 'monetizationstop' events.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// This event fires when Web Monetization has stopped.&lt;/span&gt;
&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onStop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// Stream that tracks 'monetizationprogress' events.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// This event fires when Web Monetization has streamed a payment.&lt;/span&gt;
&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;onProgress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But all of this functionality only works if you have a payment pointer defined in a &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tag in the HTML. This can be achieved initializing a &lt;code&gt;Monetization&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:monetization/monetization.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;monetization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Monetization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="si"&gt;$pay&lt;/span&gt;&lt;span class="s"&gt;.tomasarias.me'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, all the set up is done by the package, no need to edit the HTML or do Dart-JS interoperability. This is especially useful on Flutter Web where DOM manipulation or calling JavaScript is very rare.&lt;/p&gt;

&lt;p&gt;This is where we began extending beyond the JavaScript API, for example, we can get information about the monetization status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isMonetized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Returns if the user supports monetization&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPaying&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// Returns if the user is streaming payments&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// Returns the current payment pointer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or even get the revenue paid to the current payment pointer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTotal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 884389&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;formatted:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0.000884389&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assetCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// 'XRP'&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assetScale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 9&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another useful thing we could do is programatically enable or disable the monetization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;monetization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Monetization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="si"&gt;$pay&lt;/span&gt;&lt;span class="s"&gt;.tomasarias.me'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Monetization enabled on initialization&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Stops the monetization&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Start the monetization again with the same pointer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to share the revenue across different payment pointers, probabilistic revenue sharing is also supported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;pointers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;'pay.tomasarias.me/usd'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'pay.tomasarias.me/xrp'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'pay.tomasarias.me/ars'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;monetization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;probabilistic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pointers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will result in a 50% chance of choosing the first pointer, a 20% chance of choosing the second, and a 30% chance of choosing the third one.&lt;/p&gt;

&lt;p&gt;One of the last features we are going to explore is the ability to verify the payment stream and anonymizing the payment pointer.&lt;/p&gt;

&lt;p&gt;Verifying the payments is complex and not very straightforward at the moment (at least until STREAM Receipts are fully adopted). Thankfully there is a service that can do that for us, &lt;a href="https://vanilla.so" rel="noopener noreferrer"&gt;Vanilla&lt;/a&gt; keeps your information more secure and ensures users don’t cheat their way around the payment mechanism. To learn more about Vanilla check out &lt;a href="https://dev.to/cinnamonvideo/vanilla-by-cinnamon-497"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use Vanilla with &lt;code&gt;Monetization&lt;/code&gt; we can initialize it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Vanilla API Credentials&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Your Client ID'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Your Client Secret'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;monetization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vanilla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can check if the payment stream is valid in different ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// With Vanilla, this will return true if the user is paying and Vanilla generates a proof of payment.&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPaying&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// With Vanilla, this will return the current payment rate per second, if the monetization is stopped this will be 0.&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVanillaRate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// With Vanilla, this will return the total amount received from the current requestId.&lt;/span&gt;
&lt;span class="n"&gt;monetization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getVanillaTotal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives us much more confidence serving monetized content, ensuring only legit monetized users can access your content.&lt;/p&gt;

&lt;p&gt;And last but not least, a debug mode to see all the events in real-time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomasarias.me%2Fmonetization%2Fdev%2Fdebug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftomasarias.me%2Fmonetization%2Fdev%2Fdebug.png" alt="Debug mode" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to the Coil team for their &lt;a href="https://glitch.com/@coil" rel="noopener noreferrer"&gt;sample projects on Glitch&lt;/a&gt;, they were great inspiration for the features.&lt;/p&gt;

&lt;p&gt;And a special thanks to Norbert Durcansky for sharing his vision and all of the Cinnamon team for crafting &lt;a href="https://vanilla.so" rel="noopener noreferrer"&gt;Vanilla&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That would be all! 🙌 Thanks for reading and please feel free to communicate your thoughts, suggestions, or corrections.&lt;/p&gt;

</description>
      <category>gftwhackathon</category>
      <category>webmonetization</category>
      <category>dart</category>
      <category>showdev</category>
    </item>
    <item>
      <title>🧙🏼‍♂️ Embark on an adventure, just a call away!</title>
      <dc:creator>tomas</dc:creator>
      <pubDate>Fri, 01 May 2020 06:48:55 +0000</pubDate>
      <link>https://dev.to/tomas/embark-on-an-adventure-just-a-call-away-eok</link>
      <guid>https://dev.to/tomas/embark-on-an-adventure-just-a-call-away-eok</guid>
      <description>&lt;h2&gt;
  
  
  About
&lt;/h2&gt;

&lt;p&gt;Socializing during quarantine is hard, and trapped at home there is only so much that we can do by ourselves, after reading every book in my library and binged every show on Netflix I was out of stories, so what do I do now?&lt;/p&gt;

&lt;p&gt;So I built a AI-powered conversational bot to fulfill my lack of stories, not only that but take part on them too. Hey, we all enjoy a good story (or a good laugh)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Project
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/KNawm" rel="noopener noreferrer"&gt;
        KNawm
      &lt;/a&gt; / &lt;a href="https://github.com/KNawm/aidungeon-twilio" rel="noopener noreferrer"&gt;
        aidungeon-twilio
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🧙🏼‍♂️ Infinite adventures just a call away!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;a href="https://www.twilio.com" rel="nofollow noopener noreferrer"&gt;
  &lt;img src="https://camo.githubusercontent.com/eea195a24d2951c7951123105c1f23df652357460340896ac30d9c2760038a93/68747470733a2f2f737461746963302e7477696c696f2e636f6d2f6d61726b6574696e672f62756e646c65732f6d61726b6574696e672f696d672f6c6f676f732f776f72646d61726b2d7265642e737667" alt="Twilio" width="250"&gt;
&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;aidungeon-twilio&lt;/h1&gt;
&lt;/div&gt;
&lt;a href="https://github.com/KNawm/aidungeon-twilio./LICENSE" rel="noopener noreferrer"&gt;
  &lt;img src="https://camo.githubusercontent.com/0be5216e615b0012976fe492b15568b44b45912356476457ea1ef80d2a384051/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e7376673f7374796c653d666f722d7468652d6261646765" title="License"&gt;
&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;About&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This project shows how to integrate a custom machine learning model with an API to build an AI-powered conversational bot that builds a story based on your input.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Set up&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Requirements&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.4 or newer&lt;/li&gt;
&lt;li&gt;A Twilio account — &lt;a href="https://www.twilio.com/referral/CwlrIy" rel="nofollow noopener noreferrer"&gt;sign up&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A Twilio phone number with Voice capabilities&lt;/li&gt;
&lt;li&gt;A AIDungeon account — &lt;a href="https://play.aidungeon.io" rel="nofollow noopener noreferrer"&gt;sign up&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Local development&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;After the above requirements have been met:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clone this repository and &lt;code&gt;cd&lt;/code&gt; into it&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone git@github.com:KNawm/aidungeon-twilio.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; aidungeon-twilio&lt;/pre&gt;

&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Create a new virtual environment&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;python3 -m venv venv
venv&lt;span class="pl-cce"&gt;\S&lt;/span&gt;cripts&lt;span class="pl-cce"&gt;\a&lt;/span&gt;ctivate&lt;/pre&gt;

&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Install dependencies&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install -r requirements.txt&lt;/pre&gt;

&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Set your environment variables&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;cp .env.example .env&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Open &lt;code&gt;.env&lt;/code&gt; in your favorite text editor and configure the following values.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Config Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TWILIO_ACCOUNT_SID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your primary Twilio account identifier - &lt;a href="https://www.twilio.com/console" rel="nofollow noopener noreferrer"&gt;find this in the console here&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TWILIO_AUTH_TOKEN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Used to authenticate - &lt;a href="https://www.twilio.com/console" rel="nofollow noopener noreferrer"&gt;you can get it at twilio.com/console&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AIDUNGEON_EMAIL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your AIDungeon account email&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/KNawm/aidungeon-twilio" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;I used Python with Flask for the backend. It's built on top of the &lt;a href="https://aidungeon.io/" rel="noopener noreferrer"&gt;AIDungeon&lt;/a&gt; API, you just call and the bot will put together a story protagonized by you, fantasy, zombies, apocalypse, you name it, possibilities are endless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;I wanted to work with the model directly but for a lack of time I couldn't (maybe next time?). I enjoyed doing it, and I'll definitely continue working on it improving it and adding features!&lt;/p&gt;

</description>
      <category>octograd2020</category>
    </item>
  </channel>
</rss>
