mirror of https://github.com/lukechilds/docs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
24 KiB
379 lines
24 KiB
<p>In this tutorial, you build the code for and run a single-page application (SPA)
|
|
with Blockstack and Vue.js. Once the application is running, you take a tour
|
|
through the applications’ Blockstack functionality. You’ll learn how it manages
|
|
authentiation using a Blockstack ID and how it stores information associated
|
|
with that ID using Blockstack Storage (Gaia).</p>
|
|
|
|
<h2 id="prerequisites">Prerequisites</h2>
|
|
|
|
<p>Make sure you have <a href="ids-introduction#create-an-initial-blockstack-id">created at least one Blockstack ID</a>. You’ll use this ID to Finteract with the Todo application.</p>
|
|
|
|
<p>The applicaton code relies on both the <code class="highlighter-rouge">npm</code> and the <code class="highlighter-rouge">yarn</code> package managers.
|
|
Before you begin, verify you have these tools <code class="highlighter-rouge">npm</code> using the <code class="highlighter-rouge">which</code> command to
|
|
verify.</p>
|
|
|
|
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>which npm
|
|
/usr/local/bin/npm
|
|
<span class="gp">$ </span>which yarn
|
|
/usr/local/bin/yarn
|
|
</code></pre>
|
|
</div>
|
|
|
|
<p><a href="https://www.npmjs.com/get-npm">Install npm</a>, <a href="https://yarnpkg.com/lang/en/docs/install/#mac-stable">install
|
|
yarn</a>, or both as needed. You</p>
|
|
|
|
<p>While it stands alone, this tour does on the information from the <a href="hello-blockstack">Hello
|
|
Blockstack tutorial</a>. If you haven’t worked through that
|
|
tutorial, you may want to do that before continuing.</p>
|
|
|
|
<h2 id="install-the-applicaton-code-and-retrieve-the-dependencies">Install the applicaton code and retrieve the dependencies</h2>
|
|
|
|
<p>You can clone the source code with <code class="highlighter-rouge">git</code> or <a href="https://github.com/blockstack/blockstack-todos/archive/master.zip">download and unzip the code from
|
|
the
|
|
repository</a>.
|
|
These instructions assume you are cloning.</p>
|
|
|
|
<ol>
|
|
<li>
|
|
<p>Install the code by cloning it.</p>
|
|
|
|
<div class="highlighter-rouge"><pre class="highlight"><code> $ git clone git@github.com:blockstack/blockstack-todos.git
|
|
</code></pre>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<p>Change to directory to the root of the code.</p>
|
|
|
|
<div class="highlighter-rouge"><pre class="highlight"><code> $ cd blockstack-todos
|
|
</code></pre>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<p>Use yarn to install the dependencies.</p>
|
|
|
|
<div class="highlighter-rouge"><pre class="highlight"><code> $ yarn install
|
|
yarn install v1.9.2
|
|
info No lockfile found.
|
|
...
|
|
[4/5] 🔗 Linking dependencies...
|
|
[5/5] 📃 Building fresh packages...
|
|
success Saved lockfile.
|
|
✨ Done in 19.90s.
|
|
</code></pre>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
|
|
<h2 id="understand-the-important-application-files">Understand the important application files</h2>
|
|
|
|
<p>The Todo application has a basic Vue.js structure. There are several configuration files but the central programming files are in the <code class="highlighter-rouge">src</code> directory:</p>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>File</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code class="highlighter-rouge">main.js</code></td>
|
|
<td>Application initialization.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code class="highlighter-rouge">App.vue </code></td>
|
|
<td>Code for handling the <code class="highlighter-rouge">authResponse</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code class="highlighter-rouge">Landing.vue </code></td>
|
|
<td>Code for the initial sign on page.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code class="highlighter-rouge">Dashboard.vue</code></td>
|
|
<td>Application data storage and user sign out.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p>The example application runs in a node server on your local host. In the next section, you start the application and interact with it.</p>
|
|
|
|
<ol>
|
|
<li>
|
|
<p>Start the application.</p>
|
|
|
|
<div class="highlighter-rouge"><pre class="highlight"><code> $ npm run start
|
|
</code></pre>
|
|
</div>
|
|
|
|
<p>You should see a simple application:</p>
|
|
|
|
<p><img src="images/todo-sign-in.png" alt="" /></p>
|
|
</li>
|
|
<li>
|
|
<p>Choose <strong>Sign In with Blockstack</strong>.</p>
|
|
</li>
|
|
</ol>
|
|
|
|
<h2 id="understand-the-sign-in-process">Understand the sign in process</h2>
|
|
|
|
<p>At startup, the Todo application detects whether the user has the Blockstack client edition
|
|
installed or not. This is done automatically by the Blockstack API, more
|
|
about this later. What the authenticator displays depends on which whether the user has installed the Blockstack Authenticator client edition or not.</p>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Client edition installed</th>
|
|
<th>Not installed</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><img src="images/login.gif" alt="" /></td>
|
|
<td><img src="images/login-choice.png" alt="" /></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p>If the user was logged into the Blockstack authenticator (web or client) but
|
|
did not reset it, the web application to use the current identity:</p>
|
|
|
|
<p><img src="images/login-no-auth.png" alt="" /></p>
|
|
|
|
<p>If the user chooses <strong>Deny</strong>, the Blockstack authenticator opens but the user
|
|
is not logged into the sample application.</p>
|
|
|
|
<p><img src="images/windows-browser.png" alt="" /></p>
|
|
|
|
<p>If the login to the application is successful, the user is presented with the application:</p>
|
|
|
|
<p><img src="images/todo-app.png" alt="" /></p>
|
|
|
|
<p>Clicking the <strong>Sign In With Blockstack</strong> button brings up a modal that prompts
|
|
you to use an existing ID’s session, create a new ID, or reset the browser with
|
|
another ID. When Blockstack is provided an ID, it generates an <em>ephemeral key</em>
|
|
within the application. An ephemeral key is generated for each execution of a
|
|
key establishment process. This key is just used for the particular instance of
|
|
the application, in this case to sign a <strong>Sign In</strong> request.</p>
|
|
|
|
<p>Blockstack also generates a public key token which is sent to the authenticator
|
|
as an <code class="highlighter-rouge">authRequest</code> from the authenticator to your local blockstack-core node.
|
|
The signed authentication request is sent to Blockstack through a JSON Web
|
|
Token. The JWT is passed in via a URL query string in the <code class="highlighter-rouge">authRequest</code>
|
|
parameter:
|
|
<code class="highlighter-rouge">https://browser.blockstack.org/auth?authRequest=j902120cn829n1jnvoa...</code>. To
|
|
decode the token and see what information it holds:</p>
|
|
|
|
<ol>
|
|
<li>Copy the <code class="highlighter-rouge">authRequest</code> string from the URL.</li>
|
|
<li>Navigate to <a href="http://jwt.io/">jwt.io</a>.</li>
|
|
<li>
|
|
<p>Paste the full token there.</p>
|
|
|
|
<p>The output should look similar to below:</p>
|
|
|
|
<div class="language-json highlighter-rouge"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="w">
|
|
</span><span class="nt">"jti"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3i96e3ad-0626-4e32-a316-b243154212e2"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"iat"</span><span class="p">:</span><span class="w"> </span><span class="mi">1533136622</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"exp"</span><span class="p">:</span><span class="w"> </span><span class="mi">1533140228</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"iss"</span><span class="p">:</span><span class="w"> </span><span class="s2">"did:btc-addr:1Nh8oQTunbEQWjrL666HBx2qMc81puLmMt"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"public_keys"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
|
|
</span><span class="s2">"0362173da080c6e1dec0653fa9a3eff5f5660546e387ce6c24u04a90c2fe1fdu73"</span><span class="w">
|
|
</span><span class="p">],</span><span class="w">
|
|
</span><span class="nt">"domain_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:8080"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"manifest_uri"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:8080/manifest.json"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"redirect_uri"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://localhost:8080/"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.2.0"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"do_not_include_profile"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"supports_hub_url"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"scopes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
|
|
</span><span class="s2">"store_write"</span><span class="w">
|
|
</span><span class="p">]</span><span class="w">
|
|
</span><span class="p">}</span><span class="w">
|
|
</span></code></pre>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
|
|
<blockquote>
|
|
<p><strong>Note</strong>:</p>
|
|
<ol>
|
|
<li>The <code class="highlighter-rouge">iss</code> property is a decentralized identifier or <code class="highlighter-rouge">did</code>. This identifies you and your name to the application. The specific <code class="highlighter-rouge">did</code> is a <code class="highlighter-rouge">btc-addr</code>.</li>
|
|
<li>The Blockstack JWT implementation is different from other implementations because of the underlying cryptography we employ. There are libraries in <a href="https://github.com/blockstack/jsontokens-js">Javascript</a> and <a href="https://github.com/blockstack/ruby-jwt-blockstack">Ruby</a> available on the Blockstack Github to allow you to work with these tokens.</li>
|
|
</ol>
|
|
</blockquote>
|
|
|
|
<p>When the blockstack-core receives the <code class="highlighter-rouge">authRequest</code>, it generates a session token and
|
|
returns an authentication response to the application. This response is similar
|
|
to the <code class="highlighter-rouge">authRequest</code> above in that the <code class="highlighter-rouge">authResponse</code> includes a private key
|
|
intended only for the application. This allows the application to encrypt data
|
|
on your personal Blockstack storage.</p>
|
|
|
|
<p>You are now logged into the Todo application!</p>
|
|
|
|
<h2 id="undder-the-covers-in-the-sign-in-code">Undder the covers in the sign in code</h2>
|
|
|
|
<p>Now, go to the underlying <code class="highlighter-rouge">blockstack-todo</code> code you cloned or downloaded. Sign
|
|
in and sign out is handled in each of these files:</p>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>File</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code class="highlighter-rouge">App.vue </code></td>
|
|
<td>Handles the <code class="highlighter-rouge">authResponse</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code class="highlighter-rouge">Landing.vue </code></td>
|
|
<td>Generates the <code class="highlighter-rouge">authRequest</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code class="highlighter-rouge">Dashboard.vue</code></td>
|
|
<td>Handles sign out.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<p>The <code class="highlighter-rouge">src/components/Landing.vue</code> code calls a <a href="https://blockstack.github.io/blockstack.js#redirectToSignIn"><code class="highlighter-rouge">redirectToSignIn()</code></a> function which generates the <code class="highlighter-rouge">authRequest</code> and redirects the user to the Blockstack authenticator:</p>
|
|
|
|
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="nx">signIn</span> <span class="p">()</span> <span class="p">{</span>
|
|
<span class="kr">const</span> <span class="nx">blockstack</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">blockstack</span>
|
|
<span class="nx">blockstack</span><span class="p">.</span><span class="nx">redirectToSignIn</span><span class="p">()</span>
|
|
<span class="p">}</span>
|
|
</code></pre>
|
|
</div>
|
|
|
|
<p>Once the user authenticates, the application handles the <code class="highlighter-rouge">authResponse</code> in the <code class="highlighter-rouge">src/App.vue</code> file. :</p>
|
|
|
|
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="nx">blockstack</span><span class="p">.</span><span class="nx">isUserSignedIn</span><span class="p">())</span> <span class="p">{</span>
|
|
<span class="k">this</span><span class="p">.</span><span class="nx">user</span> <span class="o">=</span> <span class="nx">blockstack</span><span class="p">.</span><span class="nx">loadUserData</span><span class="p">().</span><span class="nx">profile</span>
|
|
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">blockstack</span><span class="p">.</span><span class="nx">isSignInPending</span><span class="p">())</span> <span class="p">{</span>
|
|
<span class="nx">blockstack</span><span class="p">.</span><span class="nx">handlePendingSignIn</span><span class="p">()</span>
|
|
<span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">userData</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
|
|
<span class="nb">window</span><span class="p">.</span><span class="nx">location</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">origin</span>
|
|
<span class="p">})</span>
|
|
<span class="p">}</span>
|
|
</code></pre>
|
|
</div>
|
|
|
|
<p>If <a href="https://blockstack.github.io/blockstack.js/#isusersignedin"><code class="highlighter-rouge">blockstack.isUserSignedIn()</code></a> is true, the user was previously signed in so Blockstack pulls the data from the browser and uses it in our application. If the check on <a href="https://blockstack.github.io/blockstack.js/#issigninpending"><code class="highlighter-rouge">blockstack.isSignInPending()</code></a> is true, a previous <code class="highlighter-rouge">authResponse</code> was sent to the application but hasn’t been processed yet. The <code class="highlighter-rouge">handlePendingSignIn()</code> function processes any pending sign in.</p>
|
|
|
|
<p>Signout is handled in <code class="highlighter-rouge">src/components/Dashboard.vue</code>.</p>
|
|
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="nx">signOut</span> <span class="p">()</span> <span class="p">{</span>
|
|
<span class="k">this</span><span class="p">.</span><span class="nx">blockstack</span><span class="p">.</span><span class="nx">signUserOut</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">)</span>
|
|
<span class="p">}</span>
|
|
</code></pre>
|
|
</div>
|
|
|
|
<p>The method allows the application creator to decide where to redirect the user upon Sign Out:</p>
|
|
|
|
<h2 id="working-with-the-application">Working with the application</h2>
|
|
|
|
<p>Now trying adding a few todos using the application. For example, try making a list of applications you want to see built on top of Blockstack:</p>
|
|
|
|
<p><img src="images/make-a-list.png" alt="" /></p>
|
|
|
|
<p>Each list is immediately stored in the Gaia Hub linked to your Blockstack ID.
|
|
For more information about the Gaia hub, see the <a href="https://github.com/blockstack/gaia">hub
|
|
repository</a>. You can fetch the <code class="highlighter-rouge">todos.json</code>
|
|
file you just added by opening the Javascript console and running the following
|
|
command:</p>
|
|
|
|
<pre><code class="language-Javascript">blockstack.getFile("todos.json", { decrypt: true }).then((file) => {console.log(file)})
|
|
</code></pre>
|
|
|
|
<p>You should see a JSON with the todos you just added:</p>
|
|
|
|
<div class="language-json highlighter-rouge"><pre class="highlight"><code><span class="p">[</span><span class="w">
|
|
</span><span class="p">{</span><span class="w">
|
|
</span><span class="nt">"id"</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"text"</span><span class="p">:</span><span class="s2">"Software package manager secured by the blockchain"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"completed"</span><span class="p">:</span><span class="kc">false</span><span class="w">
|
|
</span><span class="p">},</span><span class="w">
|
|
</span><span class="p">{</span><span class="w">
|
|
</span><span class="nt">"id"</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"text"</span><span class="p">:</span><span class="s2">"Mutable torrents with human readable names"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"completed"</span><span class="p">:</span><span class="kc">false</span><span class="w">
|
|
</span><span class="p">},</span><span class="w">
|
|
</span><span class="p">{</span><span class="w">
|
|
</span><span class="nt">"id"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"text"</span><span class="p">:</span><span class="s2">"Decentralized twitter"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"completed"</span><span class="p">:</span><span class="kc">false</span><span class="w">
|
|
</span><span class="p">}</span><span class="w">
|
|
</span><span class="p">]</span><span class="w">
|
|
</span></code></pre>
|
|
</div>
|
|
|
|
<p>Now, add another todo and check it off. When you fetch the newly generated file
|
|
using the Javascript console it will reflect the change look for <code class="highlighter-rouge">"completed":true</code>:</p>
|
|
|
|
<div class="language-json highlighter-rouge"><pre class="highlight"><code><span class="p">[</span><span class="w">
|
|
</span><span class="p">{</span><span class="w">
|
|
</span><span class="nt">"id"</span><span class="p">:</span><span class="mi">3</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"text"</span><span class="p">:</span><span class="s2">"Blockstack Todo"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"completed"</span><span class="p">:</span><span class="kc">true</span><span class="w">
|
|
</span><span class="p">},</span><span class="w">
|
|
</span><span class="p">{</span><span class="w">
|
|
</span><span class="nt">"id"</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"text"</span><span class="p">:</span><span class="s2">"Software package manager secured by the blockchain"</span><span class="p">,</span><span class="w">
|
|
</span><span class="nt">"completed"</span><span class="p">:</span><span class="kc">false</span><span class="w">
|
|
</span><span class="p">},</span><span class="w">
|
|
</span><span class="err">...</span><span class="w">
|
|
</span><span class="p">]</span><span class="w">
|
|
</span></code></pre>
|
|
</div>
|
|
|
|
<p>Now that you have seen the application in action, dig into how it works.</p>
|
|
|
|
<h2 id="implementing-storage">Implementing storage</h2>
|
|
|
|
<p>Now, go to the underlying <code class="highlighter-rouge">blockstack-todo</code> code you cloned or downloaded. The
|
|
application interactions with your Gaia Hub originate in the
|
|
<code class="highlighter-rouge">src/components/Dashboard.vue</code> file. First lets see where the changes to the
|
|
Todos are processed:</p>
|
|
|
|
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="nx">todos</span><span class="err">:</span> <span class="p">{</span>
|
|
<span class="nl">handler</span><span class="p">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">todos</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="kr">const</span> <span class="nx">blockstack</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">blockstack</span>
|
|
|
|
<span class="c1">// encryption is now enabled by default</span>
|
|
<span class="k">return</span> <span class="nx">blockstack</span><span class="p">.</span><span class="nx">putFile</span><span class="p">(</span><span class="nx">STORAGE_FILE</span><span class="p">,</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">todos</span><span class="p">))</span>
|
|
<span class="p">},</span>
|
|
<span class="nx">deep</span><span class="err">:</span> <span class="kc">true</span>
|
|
<span class="p">}</span>
|
|
</code></pre>
|
|
</div>
|
|
|
|
<p>Tje <code class="highlighter-rouge">todos</code> JSON object is passed in and the <a href="https://blockstack.github.io/blockstack.js/#putfile"><code class="highlighter-rouge">blockstack.putFile()</code></a> method to store it in our Gaia Hub.</p>
|
|
|
|
<p>The code needs to read the Todo items from the storage with the <a href="https://blockstack.github.io/blockstack.js/#getfile"><code class="highlighter-rouge">blockstack.getFile()</code></a> method which returns a promise:</p>
|
|
|
|
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="nx">fetchData</span> <span class="p">()</span> <span class="p">{</span>
|
|
<span class="kr">const</span> <span class="nx">blockstack</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">blockstack</span>
|
|
<span class="nx">blockstack</span><span class="p">.</span><span class="nx">getFile</span><span class="p">(</span><span class="nx">STORAGE_FILE</span><span class="p">)</span> <span class="c1">// decryption is enabled by default</span>
|
|
<span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">todosText</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
|
|
<span class="kd">var</span> <span class="nx">todos</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">todosText</span> <span class="o">||</span> <span class="s1">'[]'</span><span class="p">)</span>
|
|
<span class="nx">todos</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="nx">todo</span><span class="p">.</span><span class="nx">id</span> <span class="o">=</span> <span class="nx">index</span>
|
|
<span class="p">})</span>
|
|
<span class="k">this</span><span class="p">.</span><span class="nx">uidCount</span> <span class="o">=</span> <span class="nx">todos</span><span class="p">.</span><span class="nx">length</span>
|
|
<span class="k">this</span><span class="p">.</span><span class="nx">todos</span> <span class="o">=</span> <span class="nx">todos</span>
|
|
<span class="p">})</span>
|
|
<span class="p">},</span>
|
|
</code></pre>
|
|
</div>
|
|
|
|
<p>The <code class="highlighter-rouge">todos</code> data is retrieved from the promise.</p>
|
|
|
|
<h2 id="summary">Summary</h2>
|
|
|
|
<p>You now have everything you need to construct complex applications complete with authentication and storage on the Decentralized Internet. Why not try coding <a href="multi-player-storage.md">a sample application that accesses multiple profiles</a>.</p>
|
|
|
|
<p>If you would like to explore the Blockstack APIs, you can visit the <a href="https://core.blockstack.org/">Blockstack Core API</a> documentation or the <a href="https://blockstack.github.io/blockstack.js">Blockstack JS API</a>.</p>
|
|
|
|
<p>Go forth and build!</p>
|
|
|