82 | )
83 | }
84 | }
85 |
86 | export default App
87 |
--------------------------------------------------------------------------------
/3box-identities-ed25519/src/index.css:
--------------------------------------------------------------------------------
1 | Html, body{
2 | height:100%;
3 | }
4 |
5 | .container {
6 | display: flex; /* establish flex container */
7 | flex-direction: column; /* make main axis vertical */
8 | justify-content: center; /* center items vertically, in this case */
9 | align-items: center; /* center items horizontally, in this case */
10 | height: 300px;
11 | }
12 |
13 | .login {
14 | width: 300px;
15 | margin: 5px;
16 | text-align: center;
17 | }
18 |
19 | .login div, .login button, .login input {
20 | margin-top: 10px;
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/3box-identities-ed25519/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want your app to work offline and load faster, you can change
15 | // unregister() to register() below. Note this comes with some pitfalls.
16 | // Learn more about service workers: https://bit.ly/CRA-PWA
17 | serviceWorker.unregister();
18 |
--------------------------------------------------------------------------------
/3box-identities-ed25519/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/3box-identities-ed25519/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/3box-identities-ed25519/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/3box-identities-ed25519/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/3box-identities-ed25519/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "downlevelIteration": true,
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 textile.io
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # js-examples
2 |
3 | All code here is used as reference in the main documentation page, [docs.textile.io](https://docs.textile.io).
4 |
5 | ## Issues & Support
6 |
7 | Please open all issues on [textileio/js-textile](https://github.com/textileio/js-textile/issues) and the name or link to the specific example you are debugging.
8 |
9 | ## Use
10 |
11 | You can find each stand-alone example in each of the subdirectories.
12 |
13 | **Note**
14 |
15 | The chat demo, hub-threaddb-chat, has been temporarily deprecated until we complete the [threads refactor](https://github.com/textileio/js-threads/issues/414) project.
16 |
17 | > Examples and demos using Textile's Javascript/Typescript libraries and clients.
18 |
19 | ### bucket-photo-gallery - setup user buckets to hold files
20 |
21 | This example users non-signing keys for development mode. Here, you'll create a new user and then give them an interface to upload files to their own bucket.
22 |
23 | You can read about key generation here: https://docs.textile.io/hub/apis/.
24 |
25 | Next, you will need to update the example to use your Hub API key, https://github.com/textileio/js-examples/blob/master/bucket-photo-gallery/src/App.tsx#L19.
26 |
27 | Note: you will want to use a signing key if you use this example for a production application. Read more about that process here, https://docs.textile.io/tutorials/hub/production-auth/.
28 |
29 | #### Build & serve
30 |
31 | Change directories into the `bucket-photo-galleries` repo.
32 |
33 | ```bash
34 | npm run start
35 | ```
36 |
37 | Your browser should automatically launch to the app running on [localhost:3001](http://localhost:3001).
38 |
39 | ### hub-browser-auth-app - shows the full client/server setup to using signed api keys
40 |
41 | This example includes two Typescript projects. A server in `src/server` and a client in `src/client`. The example demonstrates how to use the [Textile Hub](https://docs.textile.io/) APIs from the Browser using user identities and **user group keys**.
42 |
43 | Read the full tutorial accompanying this example on [docs.textile.io](https://docs.textile.io).
44 |
45 | To run, you need to first copy the `example.env` folder to `.env`. Next, you need to update the key and secret fields with values you create using the Hub CLI.
46 |
47 | #### WARNING
48 |
49 | _Do not share any API Key Secrets. This includes User Group Key secret and Account key Secrets. Be sure you never commit them into public repos or share them in published apps._
50 |
51 | #### Configure
52 |
53 | Create a `.env` file in the root of your project. Ensure you never check this file into your repo or share it, it contains your User Group Key Secret.
54 |
55 | ```bash
56 | cp example.env .env
57 | ```
58 |
59 | Then replace the `USER_API_KEY` and `USER_API_SECRET` values with those you create using the Textile Hub and your own account or org (see [docs.textile.io](https://docs.textile.io) for details).
60 |
61 | #### Setup
62 |
63 | ```bash
64 | npm install
65 | ```
66 |
67 | #### Clean
68 |
69 | ```bash
70 | npm run clean
71 | ```
72 |
73 | #### Run basic auth client
74 |
75 | In this example, you can see how to create a basic user auth flow:
76 |
77 | * the user is defined by a simple keypair created in the browser on demand.
78 | * the user is then granted access to the developer's hub resources through the use of API keys.
79 | * the user can then access their own thread APIs to begin creating threads and buckets.
80 |
81 | The client code is available in `src/basic`.
82 |
83 | #### Build & serve
84 |
85 | You can run the server and client in development mode by opening two terminal windows.
86 |
87 | **Terminal 1: watch the client code**
88 |
89 | ```bash
90 | npm run dev:client
91 | ```
92 |
93 | **Terminal 2: start the dev server**
94 |
95 | ```bash
96 | npm run start:server
97 | ```
98 |
99 | You can now view the example at [localhost:3001](http://localhost:3001).
100 |
101 |
102 |
103 | ### user-mailbox-setup - demonstrates how to setup the user mailbox api
104 |
105 | This example uses a hard-coded PrivateKey as your first user's identity. It then uses the User API to enable the user's mailbox. Instead of setting up a second user, it will just send messages from the user to themselves.
106 |
107 | To use this example, you must create a Hub API key and update the code to use it.
108 |
109 | ### react-native-hub-app - demonstrates both bucket and thread functionality in react native
110 |
111 | Like many of the examples, start by copying `example.env` to `.env` and filling our key and secret values from your own Hub account.
112 |
113 | The example, when run, will go through a series of examples that set up user identity, threads, and then buckets with the Textile Hub.
114 |
115 | ### metamask-identities-ed25519 - a password based privatekey generation workflow for textile identities
116 |
117 | This example will use a user's Ethereum address and signing API from Metamask to create a new ed25519 private key identity. It does this in combination with a user supplied password. Your app never needs to store the password or private key, as the user can regenerate them at any time.
118 |
119 | You can use the identity created with any example above, your own apps, and with any Textile API for your user identities.
120 |
121 | ### 3box-identities-ed25519
122 |
123 | Similar to the above example, this example uses 3Box to derive the private key based on the user's ethereum account. It uses the box api to store the private key value on 3Box's server so it can be fetched at a future time.
124 |
125 | You can use the identity created with any example above, your own apps, and with any Textile API for your user identities.
126 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run,
6 |
7 | `npm install`
8 |
9 | To launch the example, see the Bucket app section in the main [examples readme](../README.md).
--------------------------------------------------------------------------------
/bucket-photo-gallery/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dropzone",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@textile/hub": "^6.0.1",
7 | "@types/jdenticon": "^2.2.0",
8 | "browser-image-resizer": "^2.1.0",
9 | "browser-image-size": "^1.1.0",
10 | "react": "^16.13.1",
11 | "react-dom": "^16.13.1",
12 | "react-dropzone": "^11.0.1",
13 | "react-fontawesome": "^1.7.1",
14 | "react-image-lightbox": "^5.1.1",
15 | "react-jdenticon": "0.0.8",
16 | "react-photo-gallery": "^8.0.0",
17 | "react-scripts": "3.4.1",
18 | "semantic-ui-css": "^2.4.1",
19 | "semantic-ui-react": "^0.88.2"
20 | },
21 | "devDependencies": {
22 | "@types/node": "^14.0.14",
23 | "@types/react": "^16.9.41",
24 | "@types/react-dom": "^16.9.8",
25 | "@types/react-fontawesome": "^1.6.4",
26 | "http-proxy-middleware": "^1.0.4",
27 | "typescript": "^3.9.5"
28 | },
29 | "scripts": {
30 | "start": "react-scripts start",
31 | "build": "react-scripts build",
32 | "eject": "react-scripts eject",
33 | "textile:check": "npx ncu '/^@textile/.*$/'",
34 | "textile:upgrade": "npx ncu -u '/^@textile/.*$/'"
35 | },
36 | "eslintConfig": {
37 | "extends": "react-app"
38 | },
39 | "browserslist": {
40 | "production": [
41 | ">0.2%",
42 | "not dead",
43 | "not op_mini all"
44 | ],
45 | "development": [
46 | "last 1 chrome version",
47 | "last 1 firefox version",
48 | "last 1 safari version"
49 | ]
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/js-examples/a8a5a9fe8cf8331f0bc4f811791e15dbc0597469/bucket-photo-gallery/public/favicon.ico
--------------------------------------------------------------------------------
/bucket-photo-gallery/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/js-examples/a8a5a9fe8cf8331f0bc4f811791e15dbc0597469/bucket-photo-gallery/public/logo192.png
--------------------------------------------------------------------------------
/bucket-photo-gallery/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textileio/js-examples/a8a5a9fe8cf8331f0bc4f811791e15dbc0597469/bucket-photo-gallery/public/logo512.png
--------------------------------------------------------------------------------
/bucket-photo-gallery/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/App.css:
--------------------------------------------------------------------------------
1 | .App .nav {
2 | padding-left: 20px;
3 | padding-right: 20px;
4 | background-color: #333;
5 | justify-content: center;
6 | }
7 |
8 | .App .avatar {
9 | background: none;
10 | border-radius: 5px;
11 | width: 45px; height: 45px;
12 | background: #f3f3f3;
13 | display: flex;
14 | justify-content: center;
15 | align-content: center;
16 | }
17 |
18 | .App button.link {
19 | border-radius: 5px;
20 | height: 45px;
21 | display: block;
22 | align-items: center;
23 | justify-content: center;
24 | background: none;
25 | cursor: pointer;
26 | color: #8f95ff;
27 | font-size: 12px;
28 | outline: 0;
29 | }
30 |
31 | .App .avatar svg {
32 | width: 45px; height: 45px;
33 | }
34 |
35 | .App .rendering {
36 | opacity: 0.1
37 | }
38 |
39 | .App .dropzone-container {
40 | border-radius: 5px;
41 | width: 155px; height: 45px;
42 | display: flex;
43 | align-items: center;
44 | justify-content: space-around;
45 | background: #f3f3f3;
46 | cursor: pointer;
47 | outline: 0;
48 | }
49 |
50 | .App .dropzone-container .dropzone {
51 | outline: 0;
52 | }
53 | .App .dropzone-container .dropzone span {
54 | vertical-align: middle;
55 | margin-right: 10px;
56 | font-size: 10px;
57 | font-weight: 100;
58 | color: #bbb;
59 | }
60 |
61 | .App .dropzone-container:hover {
62 | background: #ddd;
63 | }
64 |
65 | .App .dropzone-container .icon{
66 | background: none;
67 | color: #8f95ff;
68 | outline: 0;
69 | }
70 | .App .dropzone-container .icon:hover{
71 | background: none;
72 | }
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/Avatar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // @ts-ignore
3 | import Jdenticon from 'react-jdenticon';
4 | import './App.css';
5 |
6 | export interface AvatarProps { identity: string }
7 | class Avatar extends React.Component{
8 |
9 | render(){
10 | return(
11 |
12 | )
13 | }
14 | }
15 | export default Avatar;
16 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/Photos.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Gallery, { PhotoProps } from 'react-photo-gallery'
3 | import './App.css';
4 |
5 | export interface PhotosProps { photos: Array}
6 | class Photos extends React.Component{
7 | constructor(props: PhotosProps){
8 | super(props);
9 | this.state = { currentImage: 0 };
10 | }
11 |
12 | shouldComponentUpdate(nextProps: PhotosProps) {
13 | return this.props.photos.length !== nextProps.photos.length;
14 | }
15 |
16 | render(){
17 | return(
18 |
19 |
20 |
21 | )
22 | }
23 | }
24 | export default Photos;
25 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/Types.ts:
--------------------------------------------------------------------------------
1 | import { Buckets, Identity, UserAuth } from '@textile/hub'
2 | import { PhotoProps } from 'react-photo-gallery'
3 |
4 | export interface PhotoSample {
5 | cid: string
6 | name: string
7 | path: string
8 | width: number
9 | height: number
10 | }
11 | export interface Photo {
12 | date: number
13 | name: string
14 | original: PhotoSample
15 | preview: PhotoSample
16 | thumb: PhotoSample
17 | }
18 |
19 | export interface GalleryIndex {
20 | author: string
21 | date: number
22 | paths: string[]
23 | }
24 |
25 | export interface AppState {
26 | metadata: Array
27 | photos: Array
28 | index: GalleryIndex
29 | isLoading: boolean
30 | isDragActive: boolean
31 | identity?: Identity
32 | userAuth?: UserAuth
33 | buckets?: Buckets
34 | bucketKey?: string
35 | www?: string
36 | url?: string
37 | ipns?: string
38 | }
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want your app to work offline and load faster, you can change
15 | // unregister() to register() below. Note this comes with some pitfalls.
16 | // Learn more about service workers: https://bit.ly/CRA-PWA
17 | serviceWorker.unregister();
18 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/bucket-photo-gallery/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "downlevelIteration": true,
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/hub-browser-auth-app/README.md:
--------------------------------------------------------------------------------
1 | ## Available Scripts
2 |
3 | In the project directory, you can run,
4 |
5 | `npm install`
6 |
7 | To launch the example, see the Auth app section in the main [examples readme](../README.md).
--------------------------------------------------------------------------------
/hub-browser-auth-app/example.env:
--------------------------------------------------------------------------------
1 | PORT=3001
2 | SKIP_PREFLIGHT_CHECK=true
3 |
4 | # Create and use secure hub keys (with signing ENABLED)
5 | USER_API_KEY=alkjsdfls
6 | USER_API_SECRET=alkgfjwejfw;ejkf
--------------------------------------------------------------------------------
/hub-browser-auth-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "koa-server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "clean": "rimraf dist",
8 | "start:server": "npm run build:server && run-p watch:server dev:server",
9 | "build:server": "tsc -p src/server/",
10 | "dev:server": "node-dev --respawn dist/server/index.js",
11 | "watch:server": "tsc -p src/server/ -w",
12 | "dev:client": "npm run build:client && webpack --config=webpack.client.js --watch",
13 | "build:client": "webpack --config=webpack.client.js",
14 | "textile:check": "npx ncu '/^@textile/.*$/'",
15 | "textile:upgrade": "npx ncu -u '/^@textile/.*$/'"
16 | },
17 | "keywords": [],
18 | "author": "",
19 | "license": "MIT",
20 | "dependencies": {
21 | "@koa/cors": "^3.1.0",
22 | "@textile/hub": "^6.0.1",
23 | "dotenv": "^8.2.0",
24 | "emittery": "^0.7.0",
25 | "jdenticon": "^2.2.0",
26 | "koa": "^2.12.0",
27 | "koa-bodyparser": "^4.3.0",
28 | "koa-json": "^2.0.2",
29 | "koa-logger": "^3.2.1",
30 | "koa-route": "^3.2.0",
31 | "koa-router": "^8.0.8",
32 | "koa-send": "^5.0.0",
33 | "koa-static": "^5.0.0",
34 | "koa-websocket": "^6.0.0"
35 | },
36 | "devDependencies": {
37 | "@types/koa": "^2.11.3",
38 | "@types/koa-bodyparser": "^4.3.0",
39 | "@types/koa-json": "^2.0.18",
40 | "@types/koa-logger": "^3.1.1",
41 | "@types/koa-router": "^7.4.1",
42 | "@types/lodash": "^4.14.153",
43 | "chai": "^4.2.0",
44 | "chai-http": "^4.3.0",
45 | "copy-webpack-plugin": "^6.0.1",
46 | "expose-loader": "^0.7.5",
47 | "http-server": "^0.12.3",
48 | "lodash": "^4.17.15",
49 | "mocha": "^7.2.0",
50 | "node-dev": "^4.0.0",
51 | "npm-check-updates": "^6.0.1",
52 | "npm-run-all": "^4.1.5",
53 | "rimraf": "^3.0.2",
54 | "ts-loader": "^7.0.5",
55 | "ts-node-dev": "^1.0.0-pre.44",
56 | "tsconfig-paths-webpack-plugin": "^3.2.0",
57 | "typescript": "^3.9.3",
58 | "webpack": "^4.42.0",
59 | "webpack-cli": "^3.3.11"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/hub-browser-auth-app/src/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Textile Hub - Token Demo
6 |
7 |
15 |
16 |
17 |