├── .eslintignore
├── .eslintrc.cjs
├── .github
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── playwright.yml
│ └── publish.yml
├── .gitignore
├── .npmrc
├── .prettierrc.cjs
├── LICENSE
├── README.md
├── fission.yaml
├── package-lock.json
├── package.json
├── playwright.config.ts
├── postcss.config.cjs
├── src
├── app.html
├── components
│ ├── Footer.svelte
│ ├── Header.svelte
│ ├── about
│ │ └── AboutThisTemplate.svelte
│ ├── auth
│ │ ├── backup
│ │ │ ├── AreYouSure.svelte
│ │ │ └── Backup.svelte
│ │ ├── delegate-account
│ │ │ ├── ConnectBackupDevice.svelte
│ │ │ └── DelegateAccount.svelte
│ │ ├── link-device
│ │ │ └── LinkDevice.svelte
│ │ ├── recover
│ │ │ ├── HasRecoveryKit.svelte
│ │ │ └── RecoveryKitButton.svelte
│ │ └── register
│ │ │ ├── Register.svelte
│ │ │ └── Welcome.svelte
│ ├── common
│ │ ├── FilesystemActivity.svelte
│ │ ├── FullScreenLoadingSpinner.svelte
│ │ └── LoadingSpinner.svelte
│ ├── home
│ │ ├── Authed.svelte
│ │ └── Public.svelte
│ ├── icons
│ │ ├── About.svelte
│ │ ├── Alert.svelte
│ │ ├── BrandLogo.svelte
│ │ ├── BrandWordmark.svelte
│ │ ├── CheckIcon.svelte
│ │ ├── CheckThinIcon.svelte
│ │ ├── ClipboardIcon.svelte
│ │ ├── Connect.svelte
│ │ ├── DarkMode.svelte
│ │ ├── Disconnect.svelte
│ │ ├── Discord.svelte
│ │ ├── Download.svelte
│ │ ├── ExternalLink.svelte
│ │ ├── FileUploadIcon.svelte
│ │ ├── Github.svelte
│ │ ├── Hamburger.svelte
│ │ ├── Home.svelte
│ │ ├── InfoThinIcon.svelte
│ │ ├── LeftArrow.svelte
│ │ ├── LightMode.svelte
│ │ ├── OnePassword.svelte
│ │ ├── PhotoGallery.svelte
│ │ ├── RightArrow.svelte
│ │ ├── Settings.svelte
│ │ ├── Share.svelte
│ │ ├── Shield.svelte
│ │ ├── Trash.svelte
│ │ ├── Upload.svelte
│ │ ├── WarningThinIcon.svelte
│ │ ├── WelcomeCheckIcon.svelte
│ │ ├── XIcon.svelte
│ │ └── XThinIcon.svelte
│ ├── nav
│ │ ├── AlphaTag.svelte
│ │ ├── NavItem.svelte
│ │ └── SidebarNav.svelte
│ ├── notifications
│ │ ├── Notification.svelte
│ │ └── Notifications.svelte
│ └── settings
│ │ ├── Avatar.svelte
│ │ ├── AvatarUpload.svelte
│ │ ├── ConnectedDevices.svelte
│ │ ├── RecoveryKit.svelte
│ │ ├── RecoveryKitModal.svelte
│ │ ├── ThemePreferences.svelte
│ │ ├── TruncatedUsername.svelte
│ │ └── Username.svelte
├── global.css
├── global.d.ts
├── lib
│ ├── account-settings.ts
│ ├── app-info.ts
│ ├── auth
│ │ ├── account.ts
│ │ ├── backup.ts
│ │ └── linking.ts
│ ├── init.ts
│ ├── notifications.ts
│ ├── session.ts
│ ├── theme.ts
│ ├── utils.ts
│ └── views.ts
├── routes
│ ├── +error.svelte
│ ├── +layout.js
│ ├── +layout.svelte
│ ├── +page.svelte
│ ├── about
│ │ └── +page.svelte
│ ├── backup
│ │ └── +page.svelte
│ ├── delegate-account
│ │ └── +page.svelte
│ ├── gallery
│ │ ├── +page.svelte
│ │ ├── components
│ │ │ ├── icons
│ │ │ │ └── FileUploadIcon.svelte
│ │ │ ├── imageGallery
│ │ │ │ ├── ImageCard.svelte
│ │ │ │ ├── ImageGallery.svelte
│ │ │ │ └── ImageModal.svelte
│ │ │ └── upload
│ │ │ │ ├── Dropzone.svelte
│ │ │ │ └── FileUploadCard.svelte
│ │ ├── lib
│ │ │ └── gallery.ts
│ │ └── stores.ts
│ ├── link-device
│ │ └── +page.svelte
│ ├── recover
│ │ └── +page.svelte
│ ├── register
│ │ └── +page.svelte
│ └── settings
│ │ └── +page.svelte
└── stores.ts
├── static
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── apple-touch-icon.png
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon-dark.ico
├── favicon-light.ico
├── favicon.ico
├── fonts
│ ├── uncut-sans-bold-webfont.woff
│ ├── uncut-sans-bold-webfont.woff2
│ ├── uncut-sans-medium-webfont.woff
│ ├── uncut-sans-medium-webfont.woff2
│ ├── uncut-sans-regular-webfont.woff
│ └── uncut-sans-regular-webfont.woff2
├── icon-192.png
├── icon-512.png
├── icon.svg
├── ipfs-404.html
├── manifest.webmanifest
├── mstile-144x144.png
├── mstile-150x150.png
├── mstile-310x150.png
├── mstile-310x310.png
├── mstile-70x70.png
├── odd-ui.png
├── preview.png
├── safari-pinned-tab.svg
├── still-circle-animation.svg
├── style
│ └── output.css
├── wn-404.gif
└── wnfs-gallery-screenshot.png
├── svelte.config.js
├── tailwind.config.cjs
├── tests
└── homepage.spec.ts
├── tsconfig.json
├── tsnode-loader.js
└── vite.config.ts
/.eslintignore:
--------------------------------------------------------------------------------
1 | .eslintrc.cjs
2 | svelte.config.js
3 | tsnode-loader.js
4 | src/hooks.ts
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | parserOptions: {
4 | ecmaVersion: 2020,
5 | sourceType: 'module',
6 | tsconfigRootDir: __dirname,
7 | project: ['./tsconfig.json'],
8 | extraFileExtensions: ['.svelte']
9 | },
10 | env: {
11 | es6: true,
12 | browser: true
13 | },
14 | settings: {
15 | 'svelte3/typescript': () => require('typescript'),
16 | },
17 | plugins: ['svelte3', '@typescript-eslint'],
18 | ignorePatterns: ['node_modules'],
19 | extends: [
20 | 'eslint:recommended',
21 | 'plugin:@typescript-eslint/recommended',
22 | // 'plugin:@typescript-eslint/recommended-requiring-type-checking'
23 | ],
24 | overrides: [
25 | {
26 | files: ['*.svelte'],
27 | processor: 'svelte3/svelte3'
28 | }
29 | ],
30 | rules: {
31 | "@typescript-eslint/ban-ts-comment": ['error', { 'ts-ignore': 'allow-with-description'}],
32 | '@typescript-eslint/member-delimiter-style': ['error', {
33 | 'multiline': {
34 | 'delimiter': 'none',
35 | 'requireLast': false
36 | }
37 | }],
38 | '@typescript-eslint/no-use-before-define': ['off'],
39 | '@typescript-eslint/semi': ['error', 'never'],
40 | '@typescript-eslint/quotes': ['error', 'single', {
41 | allowTemplateLiterals: true
42 | }],
43 | // If you want to *intentionally* run a promise without awaiting, prepend it with "void " instead of "await "
44 | '@typescript-eslint/no-floating-promises': ['error']
45 | }
46 | }
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
4 |
5 | ## Link to issue
6 |
7 | Please add a link to any relevant issues/tickets
8 |
9 | ## Type of change
10 |
11 | Please delete options that are not relevant.
12 |
13 | - [ ] Bug fix (non-breaking change that fixes an issue)
14 | - [ ] New feature (non-breaking change that adds functionality)
15 | - [ ] Refactor (non-breaking change that updates existing functionality)
16 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
17 | - [ ] This change requires a documentation update
18 | - [ ] Comments have been added/updated
19 |
20 | ## Screenshots/Screencaps
21 |
22 | Please add previews of any UI Changes
23 |
--------------------------------------------------------------------------------
/.github/workflows/playwright.yml:
--------------------------------------------------------------------------------
1 | name: Playwright Tests
2 | on:
3 | pull_request:
4 | branches:
5 | - main
6 |
7 | jobs:
8 | test_setup:
9 | name: Test setup
10 | runs-on: ubuntu-latest
11 | outputs:
12 | preview_url: ${{ steps.waitForVercelPreviewDeployment.outputs.url }}
13 | steps:
14 | - name: Wait for Vercel preview deployment to be ready
15 | uses: patrickedqvist/wait-for-vercel-preview@main
16 | id: waitForVercelPreviewDeployment
17 | with:
18 | token: ${{ secrets.GITHUB_TOKEN }}
19 | max_timeout: 300
20 | test_e2e:
21 | needs: test_setup
22 | name: Playwright tests
23 | timeout-minutes: 5
24 | runs-on: ubuntu-latest
25 | steps:
26 | - name: Prepare testing env
27 | uses: actions/checkout@v2
28 | - uses: actions/setup-node@v2
29 | with:
30 | node-version: "16"
31 | - run: npm ci
32 | - run: npx playwright install --with-deps
33 | - name: Run tests
34 | run: npm run test:e2e
35 | env:
36 | PLAYWRIGHT_TEST_BASE_URL: ${{ needs.test_setup.outputs.preview_url }}
37 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: 🚀 Publish
2 | on:
3 | push:
4 | branches:
5 | - main
6 | jobs:
7 | publish_job:
8 | name: '🚀 Publish'
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: 📥 Checkout repository
12 | uses: actions/checkout@v2
13 | - name: 🧱 Setup node
14 | uses: actions/setup-node@v2
15 | with:
16 | node-version: '16'
17 | - name: 📦 Install packages
18 | run: npm install
19 | - name: 🏗 Build assets
20 | run: npm run build
21 | - name: 🚀 Publish to production
22 | uses: fission-suite/publish-action@v1
23 | with:
24 | machine_key: ${{ secrets.FISSION_MACHINE_KEY }}
25 | app_url: odd-template.fission.app
26 | build_dir: ./build
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # node
2 | node_modules/
3 |
4 | # svelte
5 | .svelte-kit/
6 | build/
7 |
8 | # macOS
9 | .DS_Store
10 |
11 | # playwright
12 | /test-results/
13 | /playwright-report/
14 | /playwright/.cache/
15 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
--------------------------------------------------------------------------------
/.prettierrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | htmlWhitespaceSensitivity: 'ignore',
4 | semi: false,
5 | singleQuote: true,
6 | svelteBracketNewLine: true,
7 | svelteSortOrder: 'options-scripts-markup-styles',
8 | svelteStrictMode: false,
9 | svelteIndentScriptAndStyle: true,
10 | tabWidth: 2,
11 | trailingComma: 'none',
12 | overrides: [
13 | {
14 | files: '*.md',
15 | options: {
16 | tabWidth: 4,
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Fission
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 | # ODD App Template
2 |
3 | [](https://fission.codes) [](https://github.com/oddsdk/ts-odd) [](https://discord.gg/zAQBDEq) [](https://talk.fission.codes)
4 |
5 | 
6 |
7 | The ODD App Template is a clone-and-go template for building a web application using the ODD SDK, fast. Clone, customize, and deploy to have a running distributed app in mere minutes.
8 |
9 |
10 |
The ODD SDK is alpha software.
11 |
We recommend you do not develop production applications using the ODD App Template at this time. We're working on making it reliable, fast, and awesome, but we're not there yet!
12 |
13 |
14 | ## 🤔 What's The ODD SDK?
15 |
16 | [The ODD SDK](https://github.com/oddsdk/ts-odd) empowers developers to build fully distributed web applications without needing a complex back-end. The SDK provides:
17 |
18 | - user accounts (via [the browser's Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API)),
19 | - authorization (using [UCAN](https://ucan.xyz))
20 | - encrypted file storage (via the [ODD File System](https://guide.fission.codes/developers/odd/file-system-wnfs), backed by the [InterPlanetary File System](https://ipfs.io/), or IPFS)
21 | - and key management (via websockets and a two-factor auth-like flow).
22 |
23 | ODD applications work offline and store data encrypted for the user by leveraging the power of the web platform. You can read more about the ODD SDK in Fission's [ODD SDK Guide](https://guide.fission.codes/developers/odd).
24 |
25 | ## 📦 What does this template give me?
26 |
27 | ### 🥰 Silky-smooth end-user flows
28 |
29 | The ODD App Template provides a _silky-smooth user experience_ out of the box. Creating an account and linking a second device feels familiar, comfortable, and obvious. ODD SDK authentication is key-based rather than password-based, so we've focused heavily on the authentication flows, borrowing language and screens from two-factor auth flows.
30 |
31 | ### 🧱 Built with a modern web stack
32 |
33 | The app template is built with modern web technologies:
34 |
35 | - [SvelteKit](https://kit.svelte.dev/) (powered by [Vite](https://vitejs.dev/) under the hood)
36 | - [TypeScript](https://www.typescriptlang.org/)
37 | - [Tailwind](https://tailwindcss.com/)
38 | - [DaisyUI](https://daisyui.com/)
39 |
40 | ### 👩🏫 A simple ODD demo to learn from
41 |
42 | 
43 |
44 | The app template includes a functioning application: an image gallery. Check out the image gallery code to learn how an ODD application handles things like file uploads, directories, etc.
45 |
46 | ## 🚀 Getting Started
47 |
48 | You can try out the template yourself [here](https://odd-template.fission.app/).
49 |
50 | Ready? Let's go.
51 |
52 | Prerequiste: ensure you are running Node 16.14 or greater, but _not_ Node 17 (18 is fine though!).
53 |
54 | 1. Clone the repository:
55 |
56 | ```shell
57 | git clone git@github.com:oddsdk/odd-app-template.git
58 | ```
59 |
60 | 2. Navigate to the downloaded template directory:
61 |
62 | ```shell
63 | cd odd-app-template
64 | ```
65 |
66 | 3. Install the dependencies:
67 |
68 | ```shell
69 | npm install
70 | ```
71 |
72 | 4. Start the local development server:
73 |
74 | ```shell
75 | npm run dev
76 | ```
77 |
78 | 5. Navigate to `http://localhost:5173` in your web browser.
79 |
80 | ## 🛠 Customize your app
81 |
82 | The app template is designed to be easy for you to _make it your own._ Here's how:
83 |
84 | 1. Rename your application.
85 |
86 | In `/src/lib/app-info.ts`:
87 |
88 | - Change `appName` to the name of your app.
89 | - Change `appDescription` to a simple, 1-sentence description of your app.
90 | - Update `oddNamespace` with your project details.
91 | - Once you [deploy](#-deploy) your app, change `appURL` to the production URL.
92 |
93 | In `package.json`, change `name` to your application's name.
94 |
95 | 1. Customize your app's logo.
96 |
97 | - App Logo SVG can be customized in `/src/components/icons/Brand.svelte`. Target an image that is 35 pixels high.
98 | - Replace the favicon files in `/static` by following the instructions in [this blog post](https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs)
99 | - Generate a Twitter/Social Media Embed image.
100 | - In `/src/lib/app-info.ts`, change `appImageURL` to match the URL of your embed image.
101 | - In `/src/routes/+layout.svelte`, update `og:image:width` and `og:image:height` to the size of your embed image.
102 |
103 | 1. Customize the look and feel.
104 |
105 | The app template is built using [Tailwind](https://tailwindcss.com/) and [DaisyUI](https://daisyui.com/). You can customize basic theme colors by editing `/tailwind.config.css`. Check out the [DaisyUI Theme Generator](https://daisyui.com/theme-generator/) to play around with theme colors or read the [customization guide](https://daisyui.com/docs/customize/) to customize the component appearance.
106 |
107 | 1. Clear out the app's home page.
108 |
109 | The home page content is in `/src/routes/+page.svelte`. Delete everything in the file (but don't delete the file!) to start over with a blank home page.
110 |
111 | 1. Remove the image gallery demo app code.
112 |
113 | If you're not building an image gallery, you don't need the gallery demo code, except perhaps to learn from. To get rid of it, delete:
114 |
115 | - `/src/routes/gallery`
116 | - the `initializeFilesystem` function in `/src/lib/auth/account.ts` creates directories used by WNFS. Change those to what you need for your app or delete them if you're not using WNFS.
117 |
118 | 👏 You're ready to start adding custom functionality! 🚀
119 |
120 | Check out the [ODD SDK Guide](https://guide.fission.codes/developers/odd) for ODD SDK questions or [UCAN.xyz](https://ucan.xyz) for UCAN questions.
121 |
122 | ## 📛 Usernames
123 |
124 | When you go through the registration flow in WAT, the username you type in the form field has a `#{DID}` appended to it in the background. We did this to enable discord style usernames where users can share the same usernames, but have unique identifiers attached to the end to distinguish them from one another. We then create a hash of the `fullUsername`(the one with the `#{DID}` appended to the end) that is passed to the ODD SDK. So the ODD SDK only has a notion of the `hashed` username currently. This should also allow users to create usernames using emojis or non-English characters. Also, this is the only username schema that currently supports our File System recovery flow.
125 |
126 | You don’t necessarily need to follow that same pattern though. If you were to register two of the same usernames in the app without hashing them, you would be able to call `session.authStrategy.isUsernameAvailable(username)` to ensure duplicate usernames aren't present in the app. We will be working on porting some of this functionality over to the `ts-ODD` library over the next while and we will be updating the docs to reflect that.
127 |
128 | [Please take a look at our init function](https://github.com/oddsdk/odd-app-template/blob/main/src/lib/init.ts#L34-L38) to see how we are currently constructing the username schema.
129 |
130 | ## 🧨 Deploy
131 |
132 | Any static hosting platform should be supported. The ODD App Template is currently deployed on:
133 |
134 | - [Fission](#fission-app-hosting)
135 | - [Netlify](#netlify)
136 | - [Vercel](#vercel)
137 | - [Cloudflare Pages](#cloudflare-pages)
138 |
139 | ### Fission App Hosting
140 |
141 | Try out [ODD App Template on Fission](https://odd-template.fission.app)
142 |
143 | An ODD application can be published to IPFS with the [Fission CLI](https://guide.fission.codes/developers/cli) or the [Fission GitHub publish action](https://github.com/fission-suite/publish-action).
144 |
145 | **To publish with the Fission CLI:**
146 |
147 | 1. [Install the CLI](https://guide.fission.codes/developers/installation)
148 | 2. Run `fission setup` to make a Fission account
149 | 3. Run `npm run build` to build the app
150 | 4. Delete `fission.yaml`
151 | 5. Run `fission app register` to register a new Fission app (accept the `./build` directory suggestion for your build directory)
152 | 6. Run `fission app publish` to publish your app to the web
153 |
154 | Your app will be available online at the domain assigned by the register command.
155 |
156 | **To set up the GitHub publish action:**
157 |
158 | 1. Register the app with the CLI
159 | 2. Export your machine key with `base64 ~/.config/fission/key/machine_id.ed25519`
160 | 3. Add your machine key as a GH Repository secret named `FISSION_MACHINE_KEY`
161 | 4. Update the `publish.yml` with the name of your registered app
162 |
163 | See the [Fission Guide](https://guide.fission.codes/developers/installation) and the publish action README for more details.
164 |
165 | ### Netlify
166 |
167 | [](https://app.netlify.com/sites/odd/deploys)
168 |
169 | In order to deploy your ODD application on Netlify:
170 |
171 | 1. Create a new Netlify site and connect your app's git repository. (If you don't have your application stored in a git repository, you can upload the output of a [static build](#static-build).)
172 | 2. Just click Deploy. Netlify takes care of the rest. No Netlify-specific configuration is needed.
173 | 3. There is no step 3.
174 |
175 | ### Vercel
176 |
177 | Try out the [ODD App Template on Vercel](https://odd-app-template.vercel.app/).
178 |
179 | In order to deploy your ODD application on Vercel:
180 |
181 | 1. Create a new Vercel project and connect your app's git repository. (If you don't have your application stored in a git repository, you can upload the output of a [static build](#static-build).)
182 | 2. Override the default output directory and set it to `build`.
183 | 3. Deploy. That's it!
184 |
185 | ### Cloudflare Pages
186 |
187 | Try out the [ODD App Template on Cloudflare Pages](https://odd-template.pages.dev/).
188 |
189 | In order to deploy your ODD application on Cloudflare Pages:
190 |
191 | 1. Create a new Pages project and connect your app's git repository. (If you don't have your application stored in a git repository, you can upload the output of a [static build](#static-build).)
192 | 2. Select `SvelteKit` from the "Framework preset".
193 | 3. Set the "Build output directory" to `build`.
194 | 4. Under "Environment variables", add a variable with name of `NODE_VERSION` and value of `16`.
195 | 5. Add the same environment variable to the "Preview" environment.
196 | 6. Click "Save and Deploy".
197 |
198 | ### Static Build
199 |
200 | Export a static build.
201 |
202 | ```shell
203 | npm run build
204 | ```
205 |
206 | The build outputs the static site to the `build` directory.
207 |
--------------------------------------------------------------------------------
/fission.yaml:
--------------------------------------------------------------------------------
1 | ignore: []
2 | url: odd-template.fission.app
3 | build: ./build
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "odd-app-template",
3 | "version": "0.1.0",
4 | "scripts": {
5 | "dev": "vite dev",
6 | "build": "vite build",
7 | "preview": "vite preview",
8 | "test": "ava src/**/*.test.ts",
9 | "test:e2e": "playwright test",
10 | "report:e2e": "playwright show-report",
11 | "check": "svelte-check --tsconfig ./tsconfig.json",
12 | "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
13 | "lint": "eslint './src/**/*.{js,ts,svelte}'",
14 | "format": "prettier --write --plugin-search-dir=. ."
15 | },
16 | "devDependencies": {
17 | "@playwright/test": "^1.29.2",
18 | "@sveltejs/adapter-static": "^1.0.0",
19 | "@sveltejs/kit": "^1.0.1",
20 | "@tailwindcss/typography": "^0.5.2",
21 | "@types/qrcode-svg": "^1.1.1",
22 | "@typescript-eslint/eslint-plugin": "^4.33.0",
23 | "@typescript-eslint/parser": "^4.33.0",
24 | "autoprefixer": "^10.4.13",
25 | "ava": "^4.3.1",
26 | "daisyui": "^2.0.2",
27 | "eslint": "^7.32.0",
28 | "eslint-config-prettier": "^8.1.0",
29 | "eslint-plugin-svelte3": "^3.2.1",
30 | "events": "^3.3.0",
31 | "one-webcrypto": "^1.0.1",
32 | "prettier": "~2.2.1",
33 | "prettier-plugin-svelte": "^2.2.0",
34 | "svelte": "^3.34.0",
35 | "svelte-check": "^2.0.0",
36 | "svelte-preprocess": "^4.0.0",
37 | "svelte-seo": "^1.2.1",
38 | "tailwindcss": "^3.2.1",
39 | "ts-node": "^10.4.0",
40 | "tsconfig-paths": "^3.12.0",
41 | "tslib": "^2.0.0",
42 | "typescript": "^4.4.4",
43 | "vite": "^4.0.0"
44 | },
45 | "type": "module",
46 | "ava": {
47 | "extensions": {
48 | "ts": "module"
49 | },
50 | "require": [
51 | "ts-node/register",
52 | "tsconfig-paths/register"
53 | ],
54 | "nodeArguments": [
55 | "--loader=./tsnode-loader.js"
56 | ]
57 | },
58 | "dependencies": {
59 | "clipboard-copy": "^4.0.1",
60 | "qrcode-svg": "^1.1.0",
61 | "uint8arrays": "^4.0.2",
62 | "@oddjs/odd": "0.37.0"
63 | },
64 | "engines": {
65 | "node": ">=16.14"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import type { PlaywrightTestConfig } from '@playwright/test';
2 | import { devices } from '@playwright/test';
3 |
4 | /**
5 | * Read environment variables from file.
6 | * https://github.com/motdotla/dotenv
7 | */
8 | // require('dotenv').config();
9 |
10 | /**
11 | * See https://playwright.dev/docs/test-configuration.
12 | */
13 | const config: PlaywrightTestConfig = {
14 | testDir: './tests',
15 | /* Maximum time one test can run for. */
16 | timeout: 30 * 1000,
17 | expect: {
18 | /**
19 | * Maximum time expect() should wait for the condition to be met.
20 | * For example in `await expect(locator).toHaveText();`
21 | */
22 | timeout: 5000
23 | },
24 | /* Run tests in files in parallel */
25 | fullyParallel: true,
26 | /* Fail the build on CI if you accidentally left test.only in the source code. */
27 | forbidOnly: !!process.env.CI,
28 | /* Retry on CI only */
29 | retries: process.env.CI ? 2 : 0,
30 | /* Opt out of parallel tests on CI. */
31 | workers: process.env.CI ? 1 : undefined,
32 | /* Reporter to use. See https://playwright.dev/docs/test-reporters */
33 | reporter: 'html',
34 | /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
35 | use: {
36 | /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
37 | actionTimeout: 0,
38 | /* Base URL to use in actions like `await page.goto('/')`. */
39 | baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://127.0.0.1:5173',
40 |
41 | /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
42 | trace: 'on-first-retry'
43 | },
44 |
45 | /* Configure projects for major browsers */
46 | projects: [
47 | {
48 | name: 'chromium',
49 | use: {
50 | ...devices['Desktop Chrome']
51 | }
52 | },
53 |
54 | {
55 | name: 'firefox',
56 | use: {
57 | ...devices['Desktop Firefox']
58 | }
59 | },
60 |
61 | {
62 | name: 'webkit',
63 | use: {
64 | ...devices['Desktop Safari']
65 | }
66 | },
67 |
68 | /* Test against mobile viewports. */
69 | {
70 | name: 'Mobile Chrome',
71 | use: {
72 | ...devices['Pixel 5'],
73 | },
74 | },
75 | {
76 | name: 'Mobile Safari',
77 | use: {
78 | ...devices['iPhone 12'],
79 | },
80 | },
81 | ],
82 |
83 | /* Folder for test artifacts such as screenshots, videos, traces, etc. */
84 | // outputDir: 'test-results/',
85 |
86 | /* Run your local dev server before starting the tests */
87 | webServer: {
88 | command: 'npm run dev',
89 | port: 5173
90 | }
91 | }
92 |
93 | export default config;
94 |
--------------------------------------------------------------------------------
/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('tailwindcss'), require('autoprefixer')]
3 | }
4 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | %sveltekit.head%
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
15 | The ODD SDK makes it easy to implement private, encrypted, user-owned
16 | storage in your app. See it in action with our photo gallery demo.
17 |
24 | With the ODD SDK, a user’s account lives only on their connected devices —
25 | entirely under their control. It’s easy for them to connect as many
26 | devices as they’d like. For recoverability, we recommend they always
27 | connect at least two.
28 |
41 | It appears this device isn’t supported. ODD requires IndexedDB in
42 | order to function. This browser doesn’t appear to implement this API.
43 | Are you in a Firefox private window?
44 |
12 | Your recovery kit will restore access to your data in the event that you
13 | lose access to all of your connected devices. We recommend you store your
14 | kit in a safe place, separate from those devices.
15 |