├── .github └── workflows │ ├── deploy.yml │ └── update-rsjs-submodule.yml ├── .gitignore ├── .gitmodules ├── .vitepress ├── config.mts └── theme │ ├── components │ ├── Contributors.vue │ └── DeveloperFeatures.vue │ ├── index.js │ └── style.css ├── CNAME ├── README.md ├── apps.md ├── contribute.md ├── design.md ├── favicon.ico ├── get.md ├── img ├── explainer-1-traditional-webapp-scoured.svg ├── explainer-2-no-backend-scoured.svg ├── explainer-3-unhosted-scoured.svg ├── oauth-dialog.png ├── screenshot-folder-description.png ├── sponsors │ ├── 5apps.svg │ ├── duckduckgo.svg │ ├── duckduckgo2.svg │ ├── nlnet.svg │ └── whs.svg ├── webfinger-connect.png └── widget-demo.gif ├── index.md ├── package-lock.json ├── package.json ├── protocol.md ├── public ├── data │ └── contributors.json └── logo.svg ├── rs.js.index.md ├── scripts └── fetch-contributors.mjs ├── servers.md ├── unhosted.md └── wiki ├── developers.md ├── modules.md ├── notes.md └── protocol.md /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy website to Pages 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | # Allows to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 11 | permissions: 12 | contents: read 13 | pages: write 14 | id-token: write 15 | 16 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 17 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 18 | concurrency: 19 | group: pages 20 | cancel-in-progress: false 21 | 22 | jobs: 23 | # Build job 24 | build: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 0 # Not needed if lastUpdated is not enabled 31 | submodules: true 32 | - name: Setup Node 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: 20 36 | cache: npm 37 | - name: Setup Pages 38 | uses: actions/configure-pages@v4 39 | - name: Install dependencies 40 | run: npm ci 41 | - name: Build with VitePress 42 | run: npm run docs:build 43 | - name: Upload artifact 44 | uses: actions/upload-pages-artifact@v3 45 | with: 46 | path: .vitepress/dist 47 | 48 | # Deployment job 49 | deploy: 50 | environment: 51 | name: github-pages 52 | url: ${{ steps.deployment.outputs.page_url }} 53 | needs: build 54 | runs-on: ubuntu-latest 55 | name: Deploy 56 | steps: 57 | - name: Deploy to GitHub Pages 58 | id: deployment 59 | uses: actions/deploy-pages@v4 60 | -------------------------------------------------------------------------------- /.github/workflows/update-rsjs-submodule.yml: -------------------------------------------------------------------------------- 1 | name: Update rs.js submodule 2 | 3 | on: 4 | repository_dispatch: 5 | types: [rsjs-master-updated] 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | with: 14 | ssh-key: ${{secrets.RS_WEBSITE_DEPLOY}} 15 | submodules: true 16 | 17 | - name: Update Submodule 18 | run: | 19 | git submodule update --remote rs.js 20 | git config --global user.name 'GitHub Action' 21 | git config --global user.email 'action@github.com' 22 | git add . 23 | git commit -m "Update rs.js" || echo "No changes to commit" 24 | git push 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vitepress/dist 2 | .vitepress/cache 3 | _site 4 | node_modules 5 | tmp 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rs.js"] 2 | path = rs.js 3 | url = git@github.com:remotestorage/remotestorage.js.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | import rsjsConfig from '../rs.js/docs/.vitepress/config.mts' 3 | 4 | type Item = { 5 | text: string; 6 | link: string; 7 | items?: Item[]; 8 | }; 9 | 10 | const prefixLinks = (array: Item[], prefix: string) => { 11 | array.forEach(item => { 12 | if (item.link) { 13 | item.link = prefix + item.link; 14 | } 15 | if (item.items) { 16 | prefixLinks(item.items, prefix); 17 | } 18 | }); 19 | }; 20 | 21 | const rsjsSidebarConfig = rsjsConfig.themeConfig.sidebar 22 | prefixLinks(rsjsSidebarConfig, '/rs.js/docs') 23 | 24 | // https://vitepress.dev/reference/site-config 25 | export default defineConfig({ 26 | title: "remoteStorage", 27 | description: "An open protocol for per-user storage on the Web", 28 | srcExclude: ['./wiki', './rs.js/*.md'], 29 | ignoreDeadLinks: [ 30 | /^http:\/\/localhost/, 31 | ], 32 | 33 | themeConfig: { 34 | // https://vitepress.dev/reference/default-theme-config 35 | logo: "/logo.svg", 36 | externalLinkIcon: true, 37 | outline: { level: [2, 3] }, 38 | 39 | nav: [ 40 | { text: 'Home', link: '/' }, 41 | { text: 'Getting started', link: '/get' }, 42 | { text: 'remoteStorage.js', link: '/rs.js/docs' }, 43 | { text: 'Forums', link: 'https://community.remotestorage.io' }, 44 | ], 45 | 46 | sidebar: { 47 | '/': [ 48 | { 49 | items: [ 50 | { text: 'Getting started', link: '/get' }, 51 | { text: 'How it works', 52 | items: [ 53 | { text: 'Unhosted Web Apps', link: '/unhosted' }, 54 | { text: 'Protocol', link: '/protocol' }, 55 | ] 56 | }, 57 | { text: 'Apps', link: '/apps' }, 58 | { text: 'Servers', link: '/servers' }, 59 | { text: 'Contribute', link: '/contribute' }, 60 | { text: 'Design', link: '/design' }, 61 | ] 62 | } 63 | ], 64 | '/rs.js/': rsjsSidebarConfig 65 | }, 66 | 67 | socialLinks: [ 68 | { icon: 'github', link: 'https://github.com/remotestorage' }, 69 | { icon: 'mastodon', link: 'https://kosmos.social/@remotestorage' } 70 | ], 71 | 72 | editLink: { 73 | pattern: ({ filePath }) => { 74 | if (filePath.startsWith('rs.js/')) { 75 | if (filePath.startsWith('rs.js/docs/api/')) { 76 | return '/rs.js/docs/contributing/docs'; 77 | } else { 78 | return `https://github.com/remotestorage/remotestorage.js/edit/master/${filePath.slice(6)}`; 79 | } 80 | } else { 81 | return `https://github.com/remotestorage/website/edit/master/${filePath}` 82 | } 83 | } 84 | }, 85 | 86 | search: { 87 | provider: 'local' 88 | } 89 | }, 90 | 91 | async transformPageData(pageData, { siteConfig }) { 92 | if (pageData.relativePath.startsWith('rs.js')) { 93 | pageData.titleTemplate = 'remoteStorage.js' 94 | } 95 | return pageData; 96 | }, 97 | 98 | async transformHtml(code, id, ctx) { 99 | if (id.endsWith('404.html')) { 100 | const redirectScript = ` 101 | 106 | `; 107 | return code.replace('', `${redirectScript}`); 108 | } 109 | return code; 110 | } 111 | }) 112 | -------------------------------------------------------------------------------- /.vitepress/theme/components/Contributors.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 26 | 27 | 28 | 54 | -------------------------------------------------------------------------------- /.vitepress/theme/components/DeveloperFeatures.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | 18 | 30 | -------------------------------------------------------------------------------- /.vitepress/theme/index.js: -------------------------------------------------------------------------------- 1 | // https://vitepress.dev/guide/custom-theme 2 | import { h } from 'vue' 3 | import DefaultTheme from 'vitepress/theme' 4 | import DeveloperFeatures from './components/DeveloperFeatures.vue' 5 | import Contributors from './components/Contributors.vue' 6 | import './style.css' 7 | 8 | /** @type {import('vitepress').Theme} */ 9 | export default { 10 | extends: DefaultTheme, 11 | Layout: () => { 12 | return h(DefaultTheme.Layout, null, { 13 | 'home-features-after': () => h(DeveloperFeatures) 14 | // https://vitepress.dev/guide/extending-default-theme#layout-slots 15 | }) 16 | }, 17 | enhanceApp({ app, router, siteData }) { 18 | app.component('Contributors', Contributors) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.vitepress/theme/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Customize default theme styling by overriding CSS variables: 3 | * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css 4 | */ 5 | 6 | /** 7 | * Colors 8 | * 9 | * Each colors have exact same color scale system with 3 levels of solid 10 | * colors with different brightness, and 1 soft color. 11 | * 12 | * - `XXX-1`: The most solid color used mainly for colored text. It must 13 | * satisfy the contrast ratio against when used on top of `XXX-soft`. 14 | * 15 | * - `XXX-2`: The color used mainly for hover state of the button. 16 | * 17 | * - `XXX-3`: The color for solid background, such as bg color of the button. 18 | * It must satisfy the contrast ratio with pure white (#ffffff) text on 19 | * top of it. 20 | * 21 | * - `XXX-soft`: The color used for subtle background such as custom container 22 | * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors 23 | * on top of it. 24 | * 25 | * The soft color must be semi transparent alpha channel. This is crucial 26 | * because it allows adding multiple "soft" colors on top of each other 27 | * to create a accent, such as when having inline code block inside 28 | * custom containers. 29 | * 30 | * - `default`: The color used purely for subtle indication without any 31 | * special meanings attched to it such as bg color for menu hover state. 32 | * 33 | * - `brand`: Used for primary brand colors, such as link text, button with 34 | * brand theme, etc. 35 | * 36 | * - `tip`: Used to indicate useful information. The default theme uses the 37 | * brand color for this by default. 38 | * 39 | * - `warning`: Used to indicate warning to the users. Used in custom 40 | * container, badges, etc. 41 | * 42 | * - `danger`: Used to show error, or dangerous message to the users. Used 43 | * in custom container, badges, etc. 44 | * -------------------------------------------------------------------------- */ 45 | 46 | :root { 47 | --vp-c-default-1: var(--vp-c-gray-1); 48 | --vp-c-default-2: var(--vp-c-gray-2); 49 | --vp-c-default-3: var(--vp-c-gray-3); 50 | --vp-c-default-soft: var(--vp-c-gray-soft); 51 | 52 | --vp-c-brand-1: var(--vp-c-indigo-1); 53 | --vp-c-brand-2: var(--vp-c-indigo-2); 54 | --vp-c-brand-3: var(--vp-c-indigo-3); 55 | --vp-c-brand-soft: var(--vp-c-indigo-soft); 56 | 57 | --vp-c-tip-1: var(--vp-c-brand-1); 58 | --vp-c-tip-2: var(--vp-c-brand-2); 59 | --vp-c-tip-3: var(--vp-c-brand-3); 60 | --vp-c-tip-soft: var(--vp-c-brand-soft); 61 | 62 | --vp-c-warning-1: var(--vp-c-yellow-1); 63 | --vp-c-warning-2: var(--vp-c-yellow-2); 64 | --vp-c-warning-3: var(--vp-c-yellow-3); 65 | --vp-c-warning-soft: var(--vp-c-yellow-soft); 66 | 67 | --vp-c-danger-1: var(--vp-c-red-1); 68 | --vp-c-danger-2: var(--vp-c-red-2); 69 | --vp-c-danger-3: var(--vp-c-red-3); 70 | --vp-c-danger-soft: var(--vp-c-red-soft); 71 | } 72 | 73 | /** 74 | * Component: Button 75 | * -------------------------------------------------------------------------- */ 76 | 77 | :root { 78 | --vp-button-brand-border: transparent; 79 | --vp-button-brand-text: var(--vp-c-white); 80 | --vp-button-brand-bg: var(--vp-c-brand-3); 81 | --vp-button-brand-hover-border: transparent; 82 | --vp-button-brand-hover-text: var(--vp-c-white); 83 | --vp-button-brand-hover-bg: var(--vp-c-brand-2); 84 | --vp-button-brand-active-border: transparent; 85 | --vp-button-brand-active-text: var(--vp-c-white); 86 | --vp-button-brand-active-bg: var(--vp-c-brand-1); 87 | } 88 | 89 | /** 90 | * Component: Home 91 | * -------------------------------------------------------------------------- */ 92 | 93 | :root { 94 | /* --vp-home-hero-name-color: #ff4b03; */ 95 | --vp-home-hero-name-color: transparent; 96 | --vp-home-hero-name-background: -webkit-linear-gradient( 97 | 270deg, 98 | #ff6d32 30%, 99 | #ff4b03 100 | ); 101 | 102 | --vp-home-hero-image-background-image: linear-gradient( 103 | -45deg, 104 | #bd34fe 50%, 105 | #47caff 50% 106 | ); 107 | --vp-home-hero-image-filter: blur(44px); 108 | } 109 | 110 | @media (min-width: 640px) { 111 | :root { 112 | --vp-home-hero-image-filter: blur(56px); 113 | } 114 | } 115 | 116 | @media (min-width: 960px) { 117 | :root { 118 | --vp-home-hero-image-filter: blur(68px); 119 | } 120 | } 121 | 122 | /** 123 | * Component: Custom Block 124 | * -------------------------------------------------------------------------- */ 125 | 126 | :root { 127 | --vp-custom-block-tip-border: transparent; 128 | --vp-custom-block-tip-text: var(--vp-c-text-1); 129 | --vp-custom-block-tip-bg: var(--vp-c-brand-soft); 130 | --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); 131 | } 132 | 133 | /** 134 | * Component: Algolia 135 | * -------------------------------------------------------------------------- */ 136 | 137 | .DocSearch { 138 | --docsearch-primary-color: var(--vp-c-brand-1) !important; 139 | } 140 | 141 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | remotestorage.io -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # remotestorage.io 2 | 3 | This is the remoteStorage website, running on 4 | [remotestorage.io](https://remotestorage.io). 5 | 6 | ## Development 7 | 8 | The website is built using [VitePress](https://vitepress.dev/). It includes the 9 | [remoteStorage.js](https://github.com/remotestorage/remotestorage.js) 10 | documentation via a Git submodule. 11 | 12 | ### Setup 13 | 14 | With [Git](https://git-scm.com) and [node.js](https://nodejs.org) installed, 15 | and an SSH key associated with your GitHub account... 16 | 17 | Clone this repo: 18 | 19 | ```sh 20 | git clone git@github.com:remotestorage/website.git 21 | cd website 22 | ``` 23 | 24 | Initialize and fetch the rs.js submodule: 25 | 26 | ```sh 27 | git submodule update --init 28 | ``` 29 | 30 | Install the dependencies: 31 | 32 | ```sh 33 | npm install 34 | ``` 35 | 36 | ### Running 37 | 38 | Run the local dev server, which automatically updates the local preview site 39 | whenever documents are saved: 40 | 41 | ``` 42 | npm run docs:dev 43 | ``` 44 | 45 | ### Deployment 46 | 47 | The `master` branch is automatically built and deployed to GitHub Pages. 48 | -------------------------------------------------------------------------------- /apps.md: -------------------------------------------------------------------------------- 1 | # Apps 2 | 3 | The following is a list of known apps that have integrated RS as a 4 | storage/sync option. It does not claim to be complete, and some entries 5 | may be outdated. 6 | 7 | ## Web Apps 8 | 9 | 10 | 11 | ### Productivity / Office 12 | 13 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 14 | | - | - | - | - | - | 15 | | [Papiers](https://papiers.gitlab.io/) | A simple but powerful note-taking app that syncs with your own cloud. | Notes | [GitLab](https://gitlab.com/papiers) | Full [PWA](https://papiers.gitlab.io/) | 16 | | [Todonna](https://todonna.gitlab.io/) | A simple but powerful Todo app that syncs with your own cloud. | Todo | [GitLab](https://gitlab.com/todonna) | Full [PWA](https://todonna.gitlab.io/) | 17 | | [Litewrite](https://litewrite.net) | A distraction-free app for simple note taking and writing | documents / [Documents](https://github.com/litewrite/remotestorage-module-documents) | [GitHub](https://github.com/litewrite/litewrite) Needs maintainer | [Chrome Web Store](https://chrome.google.com/webstore/detail/litewrite/cbdonnipllnmnkbmeopncohocjggmdkk) Works well on mobile and desktop | 18 | | [Notes Together](https://notestogether.hominidsoftware.com/) | Toss in text and pictures. Never spend time tidying up — unless you want to! | documents | [GitHub](https://github.com/DougReeder/notes-together) | Compatible with Litewrite; installable PWA; works well on mobile and desktop | 19 | | [Encryptic](https://app.encryptic.org) | Encrypted, cloud-synced note taking app | encryptic | [GitHub](https://github.com/encryptic-team/encryptic) needs maintainer | Works well on mobile and desktop | 20 | | [Snowfall](https://snowfall.now.sh) | Workflowy / Vimflowy inspired note-taking web-app | snowfall | [GitHub](https://github.com/71/snowfall) Needs maintainer | | 21 | | [Litespread](https://www.litespread.com) | Viewer and editor for SQLite and CSV files with basic spreadsheet functionality. | litespread | [GitHub](https://github.com/karlb/litespread) | 22 | | [chainbook.bit](https://chainbook.5apps.com/) | Unhosted address book/friend list, based on Namecoin and remoteStorage | chainbook | [GitHub](https://github.com/bumi/chainbook.bit) | 23 | | [Taskrs](https://taskrs.5apps.com/) | Tasks application that aims to be compatible with CalDAV | vdir_calendars | [GitHub](https://github.com/untitaker/taskrs) | 24 | | [Do Again](https://static.karl.berlin/doagain/) | A todo list for irregularly recurring todos. | doagain | | 25 | | [templates.alhur.es](https://templates.alhur.es/) | Mixes Markdown/HTML templates with YAML data and outputs the results. | templates | [GitHub](https://github.com/fiatjaf/templates) | Saves templates and data independently on remoteStorage; useful for printing stuff. | 26 | | [Recipe Boss](https://recipes.bhdouglass.com) | A simple recipe manager that makes your recipes work for you. | recipes, groceries, grocery_categories | [GitLab](https://gitlab.com/bhdouglass/recipe-boss) | | 27 | | [Team Tool Box](https://lduboeuf.github.io/team-tool-box/) | Build teams and assign members randomly. Useful for trainers, teachers, managers or anyone else who works with or within groups | teams | [GitHub](https://github.com/lduboeuf/team-tool-box) | 28 | 29 | ### Site Builder / Wiki 30 | 31 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 32 | | - | - | - | - | - | 33 | | [Hyperdraft](https://hyperdraft.rosano.ca) | Turn your text notes into a website. | wikiavec | [GitHub](https://github.com/wikiavec/hyperdraft) | Works well on mobile and desktop | 34 | | [TiddlyWiki remoteStorage](https://tiddly.alhur.es/#%24%3A%2Fplugins%2Ffiatjaf%2FremoteStorage) | A [TiddlyWiki](https://tiddlywiki.com/) plugin that enables saving of individual tiddlers to remoteStorage. | tiddlers | [GitHub](https://github.com/fiatjaf/tiddlywiki-remotestorage) | A hosted version you can edit and share without installing anything is available on [https://tiddly.alhur.es/](https://tiddly.alhur.es/) | 35 | | [QuikWik](https://quik-wik.5apps.com/) | A small and simple Wiki which uses Markdown syntax and stores data in localStorage and remoteStorage. | wiki | [GitHub](https://github.com/maheee/QuikWik) | 36 | 37 | ### Learning / Self-Improvement 38 | 39 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 40 | | - | - | - | - | - | 41 | | [Kommit](https://kommit.rosano.ca) | Flashcards with spaced-repetition | kommit | [GitHub](https://github.com/kommitapp/kommit) | Works well on mobile and desktop | 42 | | [Emoji Log](https://emojilog.rosano.ca) | Personal tracker organized with emoji | emojilog | [GitHub](https://github.com/emojilog/emojilog) | Works well on mobile and desktop | 43 | 44 | ### Media Consumption 45 | 46 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 47 | | - | - | - | - | - | 48 | | [Pétrolette](https://petrolette.space/) | A news aggregator / Web page that syncs using Remote Storage | petrolette | [GitLab](https://framagit.org/yphil/petrolett) | Works well on mobile and desktop | 49 | | [Àlir](https://alir.5apps.com) | Read-later app | alir | forked on [GitHub](https://github.com/rosano/alir) | Designed for mobiles, works offline | 50 | | [Joybox](https://joybox.rosano.ca) | A pinboard for audiovisual media. | joybox | [GitHub](https://github.com/joyboxapp/joybox) | Works well on mobile and desktop | 51 | | [Diffuse](https://diffuse.sh) | A music player that connects to your cloud/distributed storage | diffuse | [GitHub](https://github.com/icidasset/diffuse) | Offers RS option for storing settings, playlists, favorites etc.; works well on mobile and desktop | 52 | | [gHost](https://ghost.5apps.com/) | Unhosted photo album: store webcam photos in your remote storage | pictures | [GitHub](https://github.com/vcuculo/ghost) | 53 | 54 | ### Finance 55 | 56 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 57 | | - | - | - | - | - | 58 | | [hledger interactive](https://hledger.alhur.es/) | Parser and playground for [hledger](https://hledger.org) journals. | finance | [GitHub](https://github.com/fiatjaf/d) | Can save and load multiple journals to/from remoteStorage | 59 | | [Grouptabs](https://grouptabs.5apps.com) | Track expenses in a group of people | gruppenkasse | [GitHub](https://github.com/xMartin/grouptabs) | Best on mobile; needs shared storage account if you want to use it with a group | 60 | | [Road To FIRE](https://roadtofire.iliviu.me/) | A portfolio manager app for your stocks, ETFs, mutual funds, bonds, cryptocurrencies, commodities, P2P loans and real estate | asset-portfolio | [GitHub](https://github.com/iLiviu/road-to-fire) | Works well on mobile and desktop | 61 | 62 | ### Password 63 | 64 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 65 | | - | - | - | - | - | 66 | | [LessPass remoteStorage](https://lesspass.alhur.es/) | A new, faster [LessPass](https://lesspass.com/) widget that does autofill and saves options on remoteStorage. | lesspass | [GitHub](https://github.com/fiatjaf/lesspass-remotestorage) | [Firefox Add-on](https://addons.mozilla.org/en-US/firefox/addon/lesspass-remotestorage/) Save password profiles based on the domain you are; supports multiple profiles for each domain | 67 | | [PfP: Pain-free Passwords](https://pfp.works/) | A secure and convenient password manager that keeps you in control of your data. | pfp | [GitHub](https://github.com/palant/pfp/) | [Firefox Add-on](https://addons.mozilla.org/addon/easy-passwords/) [Chrome Extension](https://chrome.google.com/webstore/detail/pfp-pain-free-passwords/hplhaekjfmjfnfdllkpjpeenlbclffgh) [Opera Add-on](https://addons.opera.com/en/extensions/details/easy-passwords/) Syncs any number of devices via remoteStorage as long as they share the same master password; remoteStorage server doesn't have to be trusted, data is fully encrypted | 68 | 69 | ### Miscellaneous 70 | 71 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 72 | | - | - | - | - | - | 73 | | [Launchlet](https://launchlet.dev) | Run custom JavaScript or CSS on any website via bookmarklet or extension. | launchlet | [GitHub](https://github.com/launchlet/launchlet) | [Chrome Extension](https://chrome.google.com/webstore/detail/launchlet/gmgfdkajnjplpjmodjmmmkfkpjdjgnlf) [Safari Extension](https://github.com/launchlet/launchlet-extension) Works via bookmarklet or browser extension; mostly works on mobile, but best on desktop | 74 | | [Sharesome](https://sharesome.5apps.com/) | Share files quickly from your remote storage | shares | [GitHub](https://github.com/skddc/sharesome) | Best on desktop | 75 | | [Webmarks](https://webmarks.5apps.com) | Archive your bookmarks in remoteStorage | bookmarks / [bookmarks](https://www.npmjs.com/package/@remotestorage/module-bookmarks) | [GitHub](https://github.com/skddc/webmarks) | Best on desktop | 76 | | memm | Browser extension to store and tag your bookmarks with remoteStorage support | bookmarks / [bookmarks](https://www.npmjs.com/package/@remotestorage/module-bookmarks) | [GitHub](https://github.com/lesion/memm) | Compatible with Webmarks | 77 | | BookmarkVault | Web extension for securely storing and syncing bookmarks (with backup to remoteStorage) | bookmarkvault | [GitLab](https://gitlab.com/zookatron/bookmarkvault) | [Chrome extension](https://chromewebstore.google.com/detail/bookmarkvault/fhgbcoincldpdmelkhhanmdlfgafmnma), data encrypted | 78 | | [RS Location](https://rs-locate.5apps.com) | Proof-of-concept app for updating one's location profile | profile, api-keys | [Gitea](https://gitea.kosmos.org/raucao/rs-location) | [More details](https://community.remotestorage.io/t/public-protocols/627/3?u=raucao) | 79 | | [RS Inspektor](https://inspektor.5apps.com/) | A simple file browser for remoteStorage accounts | * | [GitLab](https://gitlab.com/skddc/inspektor) | Best on desktop | 80 | | [Waves](https://waves.kosmos.org/) | Log viewer for chat logs stored in RS via the chat-messages module (e.g. logged by hubot-remotestorage-logger or imported via rs-messages-importer) | chat-messages | [GitHub](https://github.com/67P/waves) | Works well on mobile and desktop | 81 | 82 | ### Sample / Tutorial 83 | 84 | | **Name** | **Description** | **Scope/Module** | **Source Code** | **Store/Catalog & Notes** | 85 | | - | - | - | - | - | 86 | | [My Favorite Drinks](https://myfavoritedrinks.remotestorage.io) | Keep a list of your favorite drinks | myfavoritedrinks | [GitHub](https://github.com/RemoteStorage/myfavoritedrinks) | Simple demo app, maintained by rs.js devs | 87 | | [Hello](https://hello.0data.app) | Simple Hello World with remoteStorage, Solid, and Fission | todos | [GitHub](https://github.com/0dataapp/hello) | Works well on mobile and desktop | 88 | | [Lucchetto Onboard](https://overhide.github.io/armadietto/lucchetto/onboard.html) | Enables in-app purchase SKU onboarding for [luchetto.js](https://www.npmjs.com/package/lucchetto/v/latest) extended RS apps | pay2my.app | [GitHub](https://github.com/overhide/armadietto/blob/master/lucchetto/onboard.html) | wide screens only; featured in the [remote-storage tutorial](https://github.com/overhide/remotestorage-tutorial) | 89 | | [AFRAME XR component](https://aframe-remotestorage.5apps.com) | Startingpoint to load/store (Web)XR scenes from/to remoteStorage | VR/AR | [Codeberg](https://codeberg.org/coderofsalvation/aframe-remotestorage) | works on mobile, desktop & VR/AR headsets | 90 | 91 | 92 | 93 | 94 | ## CLI applications, daemons, libraries 95 | 96 | | Name | Description | Scope / Module | Source Code | Store/Catalog Links | Comments/Notes | 97 | | - | - | - | - | - | - | 98 | | [remote-storage-uploader](http://github.com/fkooman/remote-storage-uploader) | Send files to public upload folder | upload | [GitHub](https://github.com/fkooman/remote-storage-uploader) | | Written in PHP | 99 | | [rs-backup](https://www.npmjs.com/package/rs-backup) | Backup and restore data from/to RS accounts | \* | [GitHub](https://github.com/skddc/rs-backup) | [NPM](https://www.npmjs.com/package/rs-backup) | Based on node.js | 100 | | [remotestorage-fuse](https://github.com/remotestorage/fuse) | Allows you to access data on any RS-compatible server via the regular filesystem | \* | [GitHub](https://github.com/remotestorage/fuse) | | 101 | | [hubot-remotestorage-logger](https://github.com/67P/hubot-remotestorage-logger) | Logs chat messages from Hubot daemons to remoteStorage accounts | chat-messages / [remotestorage-module-chat-messages](https://www.npmjs.com/package/remotestorage-module-chat-messages) | [GitHub](https://github.com/67P/hubot-remotestorage-logger) | | | 102 | | [rs-messages-importer](https://github.com/67P/rs-messages-importer) | CLI for importing log archives (currently only ZNC) to remoteStorage | chat-messages | [GitHub](https://github.com/67P/rs-messages-importer) | | | 103 | | [Unifile](https://github.com/silexlabs/unifile) | | | | | | 104 | 105 | ## Notes 106 | 107 | - Here's another list: 108 | - And another one (but not RS-only): 109 | -------------------------------------------------------------------------------- /contribute.md: -------------------------------------------------------------------------------- 1 | # What can I do for remoteStorage? 2 | 3 | ## I can code 4 | 5 | ### JavaScript 6 | 7 | * Integrate RS in any of your apps. More apps means more users, means more 8 | developers, means more apps. 9 | * Help out with the [reference 10 | client](https://github.com/remotestorage/remotestorage.js/). There are always 11 | [issues](https://github.com/remotestorage/remotestorage.js/issues) to work on 12 | * Help with completing and improving the remoteStorage.js 13 | [documentation](./rs.js/docs/) (even if 14 | it's just questions or feedback). There is more detailed information about 15 | how to [contribute to the documentation](./rs.js/docs/contributing/docs). 16 | * Contribute to any open-source remoteStorage app. Some of them are [listed 17 | here](/apps "Apps"). 18 | * Help improving and creating new remoteStorage.js [data 19 | modules](https://github.com/remotestorage/modules) 20 | * Help improving [Armadietto](https://github.com/remotestorage/armadietto/), a 21 | maintained RS server based on node.js 22 | 23 | ### PHP 24 | 25 | * Help out with [php-remote-storage](https://git.sr.ht/~fkooman/php-remote-storage), a remoteStorage server written in PHP 26 | 27 | ### Rust 28 | 29 | * Contribute to [Mysteryshack](https://github.com/untitaker/mysteryshack), a light-weight, fast, self-contained RS server 30 | 31 | ### Ruby 32 | 33 | * There is a maintained RS server implementation written in Ruby, consisting of an 34 | [accounts management app and UI](https://gitea.kosmos.org/kosmos/akkounts/) 35 | based on Rails, and a [RS HTTP API based on 36 | Sinatra](https://github.com/5apps/liquor-cabinet) 37 | * There's an [integration test 38 | suite](https://github.com/remotestorage/api-test-suite) for testing local 39 | and/or live remoteStorage servers for API compliance, which is written in 40 | Ruby (minitest/spec). 41 | 42 | ### Java 43 | 44 | * We'd like to create an Android sync adapter that synchronizes calendars and contacts. See [this thread](https://community.remotestorage.io/t/synchronization-with-carddav-caldav/307/4) if you would like to help. 45 | * Create an Android app that integrates sharing, for e.g. URLs to the bookmarks category, or images to the shares module. 46 | 47 | ### C 48 | 49 | * There's a [remoteStorage FUSE module](https://github.com/remotestorage/fuse) 50 | for mounting storages as filesystems, which needs upgrading to newer protocol 51 | versions and finishing in general. 52 | * There's a [remoteStorage server](https://github.com/remotestorage/rs-serve) 53 | written in C (with a little node.js helper app), which needs upgrading and 54 | has some installation issues. 55 | 56 | ## I can design 57 | 58 | * Improve the design of this website. The website repo is located at 59 | [https://github.com/remotestorage/website](https://github.com/remotestorage/website) 60 | * Help improve the design of any RS-enabled open source (see e.g. [apps](/apps)). Or 61 | design a new one and find a developer to help you with implementing it. 62 | 63 | ## I can write 64 | 65 | * Add and/or improve content of the RS website, or any other project-related 66 | content on the Web. 67 | * Help us improve existing technical documentation. e.g. the [remoteStorage.js 68 | docs](./rs.js/docs/) 69 | * Help improve documentation, description and marketing materials for 70 | RS-enabled open-source [apps](/apps) and [servers](/servers). 71 | * Write about remoteStorage on your website, blog, social media, etc.. Explain 72 | * the concept to users, developers, providers, and anyone else you think should 73 | know about remoteStorage's existence and how it works. 74 | * Improve the language and clarity of the [protocol 75 | specification](https://github.com/remotestorage/spec) 76 | 77 | ## I can run servers 78 | 79 | * Set up a [server](/servers) for yourself and maybe your family and 80 | friends! 81 | * Become a commercial or non-profit storage provider. You can either implement 82 | your own or use [existing server](/servers) software as your basis. 83 | 84 | ## I can test things 85 | 86 | * Use RS-enabled [apps](/apps) and/or [servers](/servers) and 87 | report issues and constructive feedback. 88 | -------------------------------------------------------------------------------- /design.md: -------------------------------------------------------------------------------- 1 | # Design 2 | 3 | ## Logo / icon 4 | 5 | 6 | 7 | The remoteStorage logo may be used, integrated, and adapted for anything 8 | related to the [protocol](protocol) or implementations of it. 9 | 10 | You can find the logo, as well as some other assets, in the [remoteStorage 11 | Design](https://github.com/remotestorage/design/) repository. 12 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remotestorage/website/30a329be5edb3707de614649e4b8b9ff9ef2aeb3/favicon.ico -------------------------------------------------------------------------------- /get.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | Here's how to use an app that allows you to connect your own storage account. 4 | 5 | ## Step 1: **Get a remoteStorage account** 🔑 6 | 7 | You might be used to signing up _with an app_, but here you sign up _with a storage provider_ so that you can use the same account with multiple apps. 8 | 9 | - If a friend or administrator has set up an account for you, get the details from them. 10 | - [5apps](https://5apps.com/storage/beta) is a commercial remoteStorage provider that currently offers free storage accounts. 11 | - A more extensive list of options can be found on the [Servers](/servers) page. 12 | 13 | ## Step 2: **Connect your storage** 🔌 14 | 15 | Once you create an account, return to the app to 'connect your storage', or explore some of the other [remoteStorage-compatible apps](/apps). 16 | -------------------------------------------------------------------------------- /img/explainer-1-traditional-webapp-scoured.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | App 7 | 8 | 9 | 10 | Data 11 | 12 | 13 | 14 | 15 | 16 | 17 | Browser 18 | 19 | 20 | -------------------------------------------------------------------------------- /img/explainer-2-no-backend-scoured.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | App 7 | 8 | 9 | 10 | Data 11 | 12 | Browser 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /img/explainer-3-unhosted-scoured.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | App 7 | 8 | 9 | 10 | Data 11 | 12 | Browser 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /img/oauth-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remotestorage/website/30a329be5edb3707de614649e4b8b9ff9ef2aeb3/img/oauth-dialog.png -------------------------------------------------------------------------------- /img/screenshot-folder-description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remotestorage/website/30a329be5edb3707de614649e4b8b9ff9ef2aeb3/img/screenshot-folder-description.png -------------------------------------------------------------------------------- /img/sponsors/5apps.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /img/sponsors/duckduckgo.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /img/sponsors/duckduckgo2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | image/svg+xml 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /img/sponsors/nlnet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | image/svg+xml 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /img/sponsors/whs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 29 | 30 | 48 | 50 | 51 | 53 | image/svg+xml 54 | 56 | 57 | 58 | 59 | 64 | 66 | 68 | 73 | 77 | 81 | 85 | 89 | 93 | 97 | 101 | 105 | 109 | 113 | 117 | 121 | 125 | 129 | 133 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /img/webfinger-connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remotestorage/website/30a329be5edb3707de614649e4b8b9ff9ef2aeb3/img/webfinger-connect.png -------------------------------------------------------------------------------- /img/widget-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remotestorage/website/30a329be5edb3707de614649e4b8b9ff9ef2aeb3/img/widget-demo.gif -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "remoteStorage" 7 | text: "An open protocol for per-user storage on the Web" 8 | tagline: "Webfinger + OAuth + CORS + REST" 9 | actions: 10 | - theme: brand 11 | text: 'Get Storage' 12 | link: '/get' 13 | 14 | - theme: alt 15 | text: How it works 16 | link: /unhosted 17 | 18 | features: 19 | - title: Own your data 20 | details: "Everything in one place – your place. Use a storage account with a provider you trust, or set up your own storage server. Move house whenever you want. It's your data." 21 | - title: Stay in sync 22 | details: "remoteStorage-enabled apps automatically sync your data across all of your devices, from desktop to tablet to smartphone, and maybe even your TV or VR headset." 23 | - title: "Compatibility & choice" 24 | details: "Use the same data across different apps. Create a to-do list in one app, and track the time on your tasks in another one. Say goodbye to app-specific data silos." 25 | - title: Go offline 26 | details: "Most remoteStorage-enabled apps come with first-class offline support. Use your apps offline on the go, and automatically sync when you're back online." 27 | 28 | devFeaturesTitle: For App Developers 🚧 29 | devFeatures: 30 | - title: Backend as a service 31 | details: "Develop your web app without worrying about hosting or developing a backend for it. Your users will connect their own backend at runtime. No more worrying about accounts, databases, passwords, etc." 32 | - title: Infinite scalability, zero cost 33 | details: "No matter if 5 hundred or 5 million people are using your app, your backend scales automatically and never costs you a single cent." 34 | - title: JS client library 35 | details: "remoteStorage.js is a JavaScript/TypeScript library that does the heavy lifting to add offline storage and cross-device synchronization to your apps." 36 | link: /rs.js/docs/ 37 | linkText: Learn more 38 | --- 39 | 40 | ## Community 41 | 42 | remoteStorage is a grass-roots standard, developed completely in the open, by the community for the community. Countless individuals have contributed in one way or another over time, and we'd love to welcome you as one of them! 43 | 44 | | | | 45 | | - | - | 46 | | [GitHub](https://github.com/remotestorage) | Where we collaborate on the protocol specification as well as all common source code. | 47 | | [Forums](https://community.remotestorage.io) | Our community exchange and support site for everybody from users to developers to providers. | 48 | | [Twitter](https://twitter.com/remotestorage_) / [Fediverse](https://kosmos.social/@remotestorage) | Follow the project on Twitter or on the Fediverse, to receive updates on releases, events, apps, and related news. | 49 | | [Mailing List](https://buttondown.email/remotestorage)| A monthly digest about remoteStorage apps, tools, and decentralized news. | 50 | | [Events](https://community.remotestorage.io/c/events) | Meet people in person at conferences, hackathons, camps, and other gatherings. | 51 | 52 | We would love for you to get involved — check out [What can I do for remoteStorage?](./contribute) for some ideas. 53 | 54 | ## Thank you to our contributors! 55 | 56 | 57 | 58 | ... and everyone not listed here! 59 | 60 | ## Sponsors 61 | 62 |
63 |

64 | 65 | NLnet Foundation 66 | 67 |

68 |

69 | 70 | 5apps 71 | 72 |

73 |

74 | 75 | Wau Holland Stiftung 76 | 77 |

78 |

79 | 80 | DuckDuckGo 81 | 82 |

83 |
84 | 85 | 99 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rs-website", 3 | "version": "1.0.0", 4 | "description": "remoteStorage Website", 5 | "directories": { 6 | "doc": "docs" 7 | }, 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "fetch-contributors": "node scripts/fetch-contributors.mjs", 11 | "docs:dev": "vitepress dev", 12 | "docs:build": "vitepress build", 13 | "docs:preview": "vitepress preview" 14 | }, 15 | "author": "remoteStorage Contributors", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "node-fetch": "^3.3.2", 19 | "vitepress": "^1.6.3", 20 | "vue": "^3.5.13" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /protocol.md: -------------------------------------------------------------------------------- 1 | # The remoteStorage Protocol 2 | 3 | remoteStorage is a creative combination of existing protocols and standards. It 4 | aims to re-use existing technologies as much as possible, adding just a small 5 | layer of standardization on top to facilitate its usage for per-user storage 6 | with simple permissions and offline-capable data sync. 7 | 8 | ## Discovery: [WebFinger](https://webfinger.net/) 9 | 10 | In order for apps to know where to ask for permissions and sync data, you 11 | give them a user address, which looks the same as an email or XMPP address 12 | (and could be one, too). With that address, apps retrieve storage information 13 | for the username on that domain/host. 14 | 15 | 17 | 18 | [Check out a live example for a 5apps 19 | user](https://client.webfinger.net/lookup?resource=tony%405apps.com). 20 | 21 | ## Authorization: [OAuth 2.0](https://oauth.net/) 22 | 23 | User data is scoped by so-called categories, which are essentially base 24 | directories, for which you can give either read-only or read/write permission. 25 | Apps will use OAuth scopes to ask for access to one or more categories. 26 | 27 | In this example screenshot, [Litewrite](https://litewrite.net/) is asking for 28 | read/write access to the "documents" category, using the OAuth scope 29 | `documents:rw`. If you allow access, the app will retrieve a bearer token, with 30 | which it can read and write to your storage, until you revoke that access on 31 | your server. 32 | 33 | 35 | 36 | ## Data Storage & Sync: [HTTP REST](https://en.wikipedia.org/wiki/Representational_state_transfer) 37 | 38 | remoteStorage defines a simple key/value store for apps to save and retrieve 39 | data. The basic operations are GET/PUT/DELETE requests for specific 40 | files/documents. 41 | 42 | In addition to that – and the only special feature aside from plain HTTP – 43 | there are directory listings, formatted as JSON-LD. They contain both the 44 | content type and size, as well as ETags, which can be used to implement sync 45 | mechanisms. The files and listings themselves also carry ETag headers for 46 | sync/caching and conditional requests. 47 | 48 | 50 | 51 | ## Specification 52 | 53 | Visit the [IETF 54 | Datatracker](https://datatracker.ietf.org/doc/html/draft-dejong-remotestorage) 55 | or [GitHub](https://github.com/remotestorage/spec) for the full protocol 56 | specification. 57 | -------------------------------------------------------------------------------- /public/data/contributors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "michielbdejong", 4 | "avatar": "https://avatars.githubusercontent.com/u/408412?v=4", 5 | "github": "https://github.com/michielbdejong", 6 | "commits": 1913 7 | }, 8 | { 9 | "name": "raucao", 10 | "avatar": "https://avatars.githubusercontent.com/u/842?v=4", 11 | "github": "https://github.com/raucao", 12 | "commits": 1346 13 | }, 14 | { 15 | "name": "nilclass", 16 | "avatar": "https://avatars.githubusercontent.com/u/104883?v=4", 17 | "github": "https://github.com/nilclass", 18 | "commits": 1203 19 | }, 20 | { 21 | "name": "galfert", 22 | "avatar": "https://avatars.githubusercontent.com/u/843?v=4", 23 | "github": "https://github.com/galfert", 24 | "commits": 553 25 | }, 26 | { 27 | "name": "lesion", 28 | "avatar": "https://avatars.githubusercontent.com/u/504700?v=4", 29 | "github": "https://github.com/lesion", 30 | "commits": 347 31 | }, 32 | { 33 | "name": "jcoglan", 34 | "avatar": "https://avatars.githubusercontent.com/u/9265?v=4", 35 | "github": "https://github.com/jcoglan", 36 | "commits": 287 37 | }, 38 | { 39 | "name": "ggrin", 40 | "avatar": "https://avatars.githubusercontent.com/u/1177635?v=4", 41 | "github": "https://github.com/ggrin", 42 | "commits": 224 43 | }, 44 | { 45 | "name": "silverbucket", 46 | "avatar": "https://avatars.githubusercontent.com/u/317571?v=4", 47 | "github": "https://github.com/silverbucket", 48 | "commits": 187 49 | }, 50 | { 51 | "name": "gregkare", 52 | "avatar": "https://avatars.githubusercontent.com/u/43297?v=4", 53 | "github": "https://github.com/gregkare", 54 | "commits": 119 55 | }, 56 | { 57 | "name": "rosano", 58 | "avatar": "https://avatars.githubusercontent.com/u/1680612?v=4", 59 | "github": "https://github.com/rosano", 60 | "commits": 99 61 | }, 62 | { 63 | "name": "DougReeder", 64 | "avatar": "https://avatars.githubusercontent.com/u/378430?v=4", 65 | "github": "https://github.com/DougReeder", 66 | "commits": 78 67 | }, 68 | { 69 | "name": "xMartin", 70 | "avatar": "https://avatars.githubusercontent.com/u/112532?v=4", 71 | "github": "https://github.com/xMartin", 72 | "commits": 67 73 | }, 74 | { 75 | "name": "jancborchardt", 76 | "avatar": "https://avatars.githubusercontent.com/u/925062?v=4", 77 | "github": "https://github.com/jancborchardt", 78 | "commits": 56 79 | }, 80 | { 81 | "name": "untitaker", 82 | "avatar": "https://avatars.githubusercontent.com/u/837573?v=4", 83 | "github": "https://github.com/untitaker", 84 | "commits": 51 85 | }, 86 | { 87 | "name": "Ragnis", 88 | "avatar": "https://avatars.githubusercontent.com/u/210148?v=4", 89 | "github": "https://github.com/Ragnis", 90 | "commits": 40 91 | }, 92 | { 93 | "name": "johannesjo", 94 | "avatar": "https://avatars.githubusercontent.com/u/1456265?v=4", 95 | "github": "https://github.com/johannesjo", 96 | "commits": 33 97 | }, 98 | { 99 | "name": "thornjad", 100 | "avatar": "https://avatars.githubusercontent.com/u/17414927?v=4", 101 | "github": "https://github.com/thornjad", 102 | "commits": 30 103 | }, 104 | { 105 | "name": "gillisig", 106 | "avatar": "https://avatars.githubusercontent.com/u/5390864?v=4", 107 | "github": "https://github.com/gillisig", 108 | "commits": 23 109 | }, 110 | { 111 | "name": "dependabot[bot]", 112 | "avatar": "https://avatars.githubusercontent.com/in/29110?v=4", 113 | "github": "https://github.com/apps/dependabot", 114 | "commits": 18 115 | }, 116 | { 117 | "name": "iLiviu", 118 | "avatar": "https://avatars.githubusercontent.com/u/11668471?v=4", 119 | "github": "https://github.com/iLiviu", 120 | "commits": 16 121 | }, 122 | { 123 | "name": "Lennie", 124 | "avatar": "https://avatars.githubusercontent.com/u/330102?v=4", 125 | "github": "https://github.com/Lennie", 126 | "commits": 15 127 | }, 128 | { 129 | "name": "clochix", 130 | "avatar": "https://avatars.githubusercontent.com/u/384908?v=4", 131 | "github": "https://github.com/clochix", 132 | "commits": 11 133 | }, 134 | { 135 | "name": "pjbollinger", 136 | "avatar": "https://avatars.githubusercontent.com/u/5209474?v=4", 137 | "github": "https://github.com/pjbollinger", 138 | "commits": 8 139 | }, 140 | { 141 | "name": "klausfl", 142 | "avatar": "https://avatars.githubusercontent.com/u/64592147?v=4", 143 | "github": "https://github.com/klausfl", 144 | "commits": 7 145 | }, 146 | { 147 | "name": "lewisl9029", 148 | "avatar": "https://avatars.githubusercontent.com/u/6934200?v=4", 149 | "github": "https://github.com/lewisl9029", 150 | "commits": 7 151 | }, 152 | { 153 | "name": "bencharp", 154 | "avatar": "https://avatars.githubusercontent.com/u/1753250?v=4", 155 | "github": "https://github.com/bencharp", 156 | "commits": 7 157 | }, 158 | { 159 | "name": "stokito", 160 | "avatar": "https://avatars.githubusercontent.com/u/415502?v=4", 161 | "github": "https://github.com/stokito", 162 | "commits": 5 163 | }, 164 | { 165 | "name": "greenkeeperio-bot", 166 | "avatar": "https://avatars.githubusercontent.com/u/14790466?v=4", 167 | "github": "https://github.com/greenkeeperio-bot", 168 | "commits": 4 169 | }, 170 | { 171 | "name": "JakubNer", 172 | "avatar": "https://avatars.githubusercontent.com/u/4973893?v=4", 173 | "github": "https://github.com/JakubNer", 174 | "commits": 4 175 | }, 176 | { 177 | "name": "steventebrinke", 178 | "avatar": "https://avatars.githubusercontent.com/u/1277338?v=4", 179 | "github": "https://github.com/steventebrinke", 180 | "commits": 3 181 | }, 182 | { 183 | "name": "jorinvo", 184 | "avatar": "https://avatars.githubusercontent.com/u/738978?v=4", 185 | "github": "https://github.com/jorinvo", 186 | "commits": 3 187 | }, 188 | { 189 | "name": "Timothee", 190 | "avatar": "https://avatars.githubusercontent.com/u/159328?v=4", 191 | "github": "https://github.com/Timothee", 192 | "commits": 3 193 | }, 194 | { 195 | "name": "kcchu", 196 | "avatar": "https://avatars.githubusercontent.com/u/800071?v=4", 197 | "github": "https://github.com/kcchu", 198 | "commits": 3 199 | }, 200 | { 201 | "name": "chicagoduane", 202 | "avatar": "https://avatars.githubusercontent.com/u/109882?v=4", 203 | "github": "https://github.com/chicagoduane", 204 | "commits": 3 205 | }, 206 | { 207 | "name": "aykevl", 208 | "avatar": "https://avatars.githubusercontent.com/u/729697?v=4", 209 | "github": "https://github.com/aykevl", 210 | "commits": 3 211 | }, 212 | { 213 | "name": "yPhil-gh", 214 | "avatar": "https://avatars.githubusercontent.com/u/1260520?v=4", 215 | "github": "https://github.com/yPhil-gh", 216 | "commits": 3 217 | }, 218 | { 219 | "name": "bibz", 220 | "avatar": "https://avatars.githubusercontent.com/u/5141956?v=4", 221 | "github": "https://github.com/bibz", 222 | "commits": 3 223 | }, 224 | { 225 | "name": "pixelkritzel", 226 | "avatar": "https://avatars.githubusercontent.com/u/1437379?v=4", 227 | "github": "https://github.com/pixelkritzel", 228 | "commits": 3 229 | }, 230 | { 231 | "name": "ssisk", 232 | "avatar": "https://avatars.githubusercontent.com/u/707137?v=4", 233 | "github": "https://github.com/ssisk", 234 | "commits": 2 235 | }, 236 | { 237 | "name": "Nezteb", 238 | "avatar": "https://avatars.githubusercontent.com/u/3588798?v=4", 239 | "github": "https://github.com/Nezteb", 240 | "commits": 2 241 | }, 242 | { 243 | "name": "kevincox", 244 | "avatar": "https://avatars.githubusercontent.com/u/494012?v=4", 245 | "github": "https://github.com/kevincox", 246 | "commits": 2 247 | }, 248 | { 249 | "name": "Vinnl", 250 | "avatar": "https://avatars.githubusercontent.com/u/4251?v=4", 251 | "github": "https://github.com/Vinnl", 252 | "commits": 2 253 | }, 254 | { 255 | "name": "jakob-dunning", 256 | "avatar": "https://avatars.githubusercontent.com/u/2395711?v=4", 257 | "github": "https://github.com/jakob-dunning", 258 | "commits": 1 259 | }, 260 | { 261 | "name": "vcuculo", 262 | "avatar": "https://avatars.githubusercontent.com/u/642555?v=4", 263 | "github": "https://github.com/vcuculo", 264 | "commits": 1 265 | }, 266 | { 267 | "name": "ebrahim-elgaml", 268 | "avatar": "https://avatars.githubusercontent.com/u/10853051?v=4", 269 | "github": "https://github.com/ebrahim-elgaml", 270 | "commits": 1 271 | }, 272 | { 273 | "name": "agrueneberg", 274 | "avatar": "https://avatars.githubusercontent.com/u/527708?v=4", 275 | "github": "https://github.com/agrueneberg", 276 | "commits": 1 277 | } 278 | ] -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /rs.js.index.md: -------------------------------------------------------------------------------- 1 | # remoteStorage.js 2 | 3 | ## At a glance 4 | 5 | ### Setup 6 | 7 | ```javascript 8 | const rs = new RemoteStorage(); 9 | rs.access.claim('todos', 'rw'); 10 | rs.caching.enable(); 11 | 12 | const client = rs.scope('/todos/'); 13 | ``` 14 | 15 | ### Write an object 16 | 17 | ```javascript 18 | // Declare an object type to validate if you want (JSON Schema) 19 | client.declareType('todo-item', {}); 20 | 21 | // Write `{"id":"alfa","done":false}` to /todos/alfa.json 22 | await client.storeObject('todo-item', 'alfa.json', { 23 | id: 'alfa', 24 | done: false, 25 | }); 26 | ``` 27 | 28 | ### Get objects 29 | 30 | ```javascript 31 | const specificItem = await client.getObject('alpha.json'); 32 | const allTodoItems = await client.getAll(); 33 | ``` 34 | 35 | ### Add the Connect Widget UI component 36 | 37 | Use our [drop-in UI widget](https://github.com/remotestorage/remotestorage-widget) for connecting remote storage accounts. 38 | 39 | ```javascript 40 | const widget = new Widget(rs); 41 | widget.attach(); 42 | ``` 43 | 44 | []() [Protocol details](/) 45 | -------------------------------------------------------------------------------- /scripts/fetch-contributors.mjs: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { promises as fs } from 'fs'; 3 | 4 | const repositories = [ 5 | 'remotestorage/spec', 6 | 'remotestorage/remotestorage.js', 7 | 'remotestorage/remotestorage-widget', 8 | 'remotestorage/modules', 9 | 'remotestorage/design', 10 | 'remotestorage/website', 11 | 'remotestorage/remotestorage.io', 12 | 'remotestorage/api-test-suite', 13 | 'remotestorage/myfavoritedrinks', 14 | 'remotestorage/armadietto', 15 | 'remotestorage/remotestorage-server', 16 | 'remotestorage/remotestorage-ruby', 17 | 'remotestorage/rs-serve', 18 | 'remotestorage/django-remotestorage', 19 | 'remotestorage/fuse', 20 | 'remotestorage/ember-cli-remotestorage', 21 | ]; 22 | 23 | const filename = './public/data/contributors.json'; 24 | 25 | const ignoredUsernames = [ 26 | 'dependabot', 27 | 'ember-tomster', 28 | ]; 29 | 30 | async function fetchContributors(repo) { 31 | try { 32 | const response = await fetch(`https://api.github.com/repos/${repo}/contributors`, { 33 | headers: { 34 | 'Accept': 'application/vnd.github.v3+json' 35 | } 36 | }); 37 | 38 | if (!response.ok) { 39 | throw new Error(`Failed to fetch contributors for ${repo}: ${response.statusText}`); 40 | } 41 | 42 | const data = await response.json(); 43 | 44 | return data.map(contributor => ({ 45 | name: contributor.login, 46 | avatar: contributor.avatar_url, 47 | github: contributor.html_url, 48 | commits: contributor.contributions 49 | })); 50 | } catch (error) { 51 | console.error(`Failed to fetch contributors for ${repo}: ${error.message}`); 52 | return []; 53 | } 54 | } 55 | 56 | async function fetchAllContributors() { 57 | let allContributors = []; 58 | 59 | for (const repo of repositories) { 60 | const contributors = await fetchContributors(repo); 61 | allContributors = allContributors.concat(contributors); 62 | } 63 | 64 | allContributors = allContributors.filter(contributor => !ignoredUsernames.includes(contributor.name)); 65 | 66 | // Aggregate contributions from the same contributor across different repositories 67 | const aggregatedContributors = allContributors.reduce((acc, contributor) => { 68 | const existing = acc.find(c => c.github === contributor.github); 69 | if (existing) { 70 | existing.commits += contributor.commits; 71 | } else { 72 | acc.push(contributor); 73 | } 74 | return acc; 75 | }, []); 76 | 77 | aggregatedContributors.sort((a, b) => b.commits - a.commits); 78 | 79 | await fs.writeFile(filename, JSON.stringify(aggregatedContributors, null, 2)); 80 | console.log(`Contributors list saved to ${filename}`); 81 | } 82 | 83 | fetchAllContributors(); 84 | -------------------------------------------------------------------------------- /servers.md: -------------------------------------------------------------------------------- 1 | # Servers 2 | 3 | ## Hosted 4 | 5 | - [5apps Storage](https://5apps.com/storage/beta) is a commercial 6 | remoteStorage provider that currently offers free storage accounts. 7 | - [Kosmos](https://kosmos.org) is an open-source cooperative that runs 8 | hosted Internet services, including remoteStorage. Signups currently by 9 | invitation only. 10 | 11 | ## Host your own 12 | 13 | - [armadietto](https://github.com/remotestorage/armadietto/) is a 14 | remoteStorage server based on node.js 15 | - [php-remote-storage](https://git.sr.ht/~fkooman/php-remote-storage) 16 | is a remoteStorage server written in PHP. ([Docker 17 | image](https://github.com/libresh/compose-remotestorage)) 18 | - [mysteryshack](https://github.com/untitaker/mysteryshack) is a 19 | remoteStorage server written in Rust. ([Docker 20 | image](https://hub.docker.com/r/bnjbvr/mysteryshack-docker/)) 21 | - [armadietto+lucchetto](https://github.com/overhide/armadietto/blob/master/lucchetto/README.md) 22 | is an [armadietto](https://github.com/remotestorage/armadietto/) fork 23 | with middleware extensions including in-app purchase support ([Docker 24 | image](https://hub.docker.com/repository/docker/overhide/armadietto)) 25 | 26 | ## Integrate into existing systems 27 | 28 | - [Liquor Cabinet](https://github.com/5apps/liquor-cabinet/) is a 29 | remoteStorage HTTP API server based on Sinatra (Ruby). It supports 30 | S3-compatible object storages and OpenStack Swift as storage 31 | backends. 32 | - [remotestorage-server](https://www.npmjs.org/package/remotestorage-server) 33 | is a node.js module, which can be used as basis for your own 34 | remoteStorage server, implementing the core HTTP behavior. 35 | 36 | ## Create a new implementation 37 | 38 | With remoteStorage being a relatively simple specification, you can write your 39 | own fully compliant server implementation in a language you like in a matter of 40 | a few days to a couple of weeks usually. 41 | 42 | You can run the [RS API Test 43 | Suite](https://github.com/remotestorage/api-test-suite) against your server 44 | from the outside to integration-test for spec compliance of the HTTP API 45 | portion of the spec. 46 | 47 | Some core contributors will gladly help you with any questions you may 48 | have on the way. There is a dedicated category for [server 49 | development](https://community.remotestorage.io/c/server-development/11) on the 50 | RS Community Forums. 51 | 52 | ## Hints for self-hosting 53 | 54 | ### Apache bug 55 | 56 | There is a [very 57 | old](https://bz.apache.org/bugzilla/show_bug.cgi?id=51223), long-running 58 | [bug in the Apache web 59 | server](https://bz.apache.org/bugzilla/show_bug.cgi?id=61820), which 60 | breaks remoteStorage sync. (In short, 304 HTTP responses get their CORS 61 | headers stripped unintentionally, so the response can never be received 62 | at an Unhosted app.) 63 | 64 | It has finally been resolved and release with Apache 2.4.47, but any version 65 | before that will not work. You need to use a server that does HTTP and CORS 66 | correctly. Most people use Nginx as a reverse proxy, but any other compliant 67 | web server works as well. 68 | 69 | ## Outdated solutions 70 | 71 | The following RS servers are not under active development anymore and 72 | need updating in order to conform to modern spec versions. If you're a 73 | developer, you might want to pick up existing code in your favorite 74 | language instead of starting from scratch: 75 | 76 | - [rs-serve](https://github.com/remotestorage/rs-serve) is a 77 | remoteStorage server written in C for POSIX systems, storing data in 78 | system users' home directories. 79 | - [python-remotestorage](https://github.com/relet/python-remotestorage) 80 | RS server for Python, using Git as storage back-end (spec: 81 | draft-dejong-remotestorage-00) 82 | - [remotestorage-ruby](https://github.com/remotestorage/remotestorage-ruby) 83 | RS server based on Ruby on Rails (spec: 2012.04) 84 | -------------------------------------------------------------------------------- /unhosted.md: -------------------------------------------------------------------------------- 1 | # Unhosted Architecture 2 | 3 | remoteStorage is the first open protocol to enable truly 4 | [unhosted](https://unhosted.org) web apps. That means users are in full control 5 | of their precious data and where it is stored, while app developers are freed 6 | of the burden of hosting, maintaining and protecting a central database. 7 | 8 | ## Traditional Web Apps 9 | 10 | In hosted web stacks such as LAMP, .Net, Ruby on Rails, Django, etc…, the 11 | developer hosts the app and data, while the user controls device. 12 | 13 | 15 | 16 | ## [No-Backend](https://nobackend.org) Web Apps 17 | 18 | In 100% client-side apps that use CouchDB, Hoodie, Firebase, Parse, Kinto, 19 | etc…, the developer provides the app and data, while user controls the device. 20 | 21 | 23 | 24 | ## [Unhosted](https://unhosted.org) Web Apps 25 | 26 | In 100% client-side apps that use remoteStorage, Google Drive, Dropbox, etc…, 27 | the developer provides only the app, while the user controls the device and 28 | data. 29 | 30 | 32 | -------------------------------------------------------------------------------- /wiki/developers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Developer portal 3 | parent: Wiki 4 | --- 5 | 6 | This page was moved from the old wiki and is in the process of being revised. 7 | 8 | ## Core 9 | 10 | - [Documentation](https://remotestoragejs.readthedocs.io/) 11 | - [GitHub](https://github.com/remotestorage/remotestorage.js/) 12 | - [npm package](https://www.npmjs.com/package/remotestoragejs) 13 | - [Adding a new storage back-end](/RemoteStorage.js:Adding_a_new_storage_back-end "RemoteStorage.js:Adding a new storage back-end") 14 | 15 | # Tips and Considerations 16 | 17 | ## Hosting 18 | 19 | ### Domains 20 | 21 | Apps should always be hosted under their own domain or subdomain, as 22 | opposed to hosting several apps in subdirectory URLs of a common domain. 23 | This is due to the Web's per-origin security model, where things like 24 | Web storage, permissions, etc. are scoped by origin, i.e. by 25 | "domain/host:port". 26 | 27 | ### HTTPS/TLS 28 | 29 | Apps should always be available via HTTPS. HTTP should redirect to the 30 | same URI on HTTPS. 31 | 32 | ## OAuth 33 | 34 | ### Client ID 35 | 36 | Due to there being no client registration for OAuth apps on the Open 37 | Web, most remoteStorage servers currently require the `client_id` 38 | parameter to be the same base URL as the `redirect_uri`. 39 | 40 | ## Private browsing 41 | 42 | remoteStorage.js supports Private/Incognito browsing mode in modern 43 | browsers. However, depending on browser support it cannot use all or any 44 | local [Web Storage](https://www.w3.org/TR/webstorage/) backends. 45 | 46 | ### Safari 47 | 48 | IndexedDB and localStorage are stubbed but not functional in Private 49 | windows (in version 9.1). RS.js stores all data in memory, so it is lost 50 | when connecting a remote storage (except for the WebFinger discovery 51 | data, which is transported via the OAuth `state` parameter). 52 | 53 | **Caveat:** do not get fooled by Safari's Web Inspector. It displays the 54 | localStorage content for the origin, but not IndexedDB. 55 | -------------------------------------------------------------------------------- /wiki/modules.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Data modules 3 | parent: Wiki 4 | --- 5 | 6 | This page was moved from the old wiki and is in the process of being revised. 7 | 8 | Data modules are **small add-on libraries** for remoteStorage.js, which 9 | extend it for storing certain types of data. App developers can create 10 | and use these modules to access and manage the same data in different 11 | apps. 12 | 13 | Data modules are currently **defined per category** (the base 14 | directories, which an app requests/receives access permissions for). For 15 | example, there's a "bookmarks" module, which can be used to manage data 16 | in the "/bookmarks" directory of a user's storage account. 17 | 18 | A module defines **data types**, which will be used to validate incoming 19 | data as well as adding [JSON-LD](https://json-ld.org/) contextual 20 | metadata. Type formats are being defined using [JSON 21 | Schema](http://json-schema.org/), and incoming data is validated against 22 | the schemas defined in the module by remoteStorage.js. 23 | 24 | ## Current status 25 | 26 | *(May 2017)* We used to maintain data modules in a single [shared 27 | repository on GitHub](https://github.com/remotestorage/modules) until 28 | recently. However, with the library layout and module loading changes in 29 | the upcoming remoteStorage.js 1.0, we decided to migrate all modules to 30 | their own user-managed repositories and use 31 | [npm](https://www.npmjs.com/) for module- and package management. 32 | 33 | We're encouraging module authors to use the tag/category/keyword 34 | "remotestorage-module" on GitHub, npm, etc. so that app developers can 35 | easily find rs.js data modules in the future. 36 | 37 | ## Resources 38 | 39 | - [Data modules 40 | documentation](https://remotestoragejs.readthedocs.io/en/latest/data-modules.html) 41 | -------------------------------------------------------------------------------- /wiki/notes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Notes 3 | parent: Wiki 4 | --- 5 | 6 | This page was moved from the wiki and is in the process of being revised. 7 | 8 | This page contains random notes, so we can quickly drop things and move 9 | them to the appropriate place later. 10 | 11 | ## Spec 12 | 13 | - Capability URLs 14 | - 15 | - 16 | - Create a more approachable explainer page, similar to 17 | and 18 | 19 | - 20 | 21 | ## IETF related work 22 | 23 | - [Internet Storage Sync 24 | (ISS)](https://github.com/labkode/Internet-Storage-Sync) ([mailing 25 | list](https://www.ietf.org/mailman/listinfo/storagesync)) 26 | 27 | ## Ideas, Approaches, Proposals 28 | 29 | - [OAuth 2.0 Authorization Server 30 | Discovery](https://www.tuxed.net/fkooman/blog/as_discovery.html) (by 31 | fkooman) 32 | - [Shared documents using 33 | remoteStorage](https://storage.5apps.com/jjg/public/documents/notes/shared/5287FE63-2A7B-4967-9219-034BCFCC2D13) 34 | - [IWC DUS](http://indiewebcamp.com/2015/Germany) 35 | - Shared folders / limited audience session 36 | - 37 | - 38 | - Linked Data 39 | - 40 | - 41 | - Maybe integrate in remotestorage browser? 42 | - [Unhosted Twitter built on 43 | RemoteStorage](http://jjg.preposter.us/unhosted-twitter-built-on-remotestorage.html) 44 | 45 | ## Integration ideas/plans 46 | 47 | - Plugin for [Known](https://withknown.com/) that lets you connect a 48 | storage and posts all the different things like status updates, 49 | check-ins, events, etc. to your storage in addition to storing it in 50 | its own database. (Needs a way for the connect to give the token 51 | from the client to the PHP backend.) 52 | 53 | ## People talking about remoteStorage elsewhere 54 | 55 | - mentions rs.js (in French): 56 | 57 | - 58 | - 59 | - 60 | 61 | ## Related work/projects/specs 62 | 63 | - 64 | - 65 | - 66 | - [Comparison table with some (not unhosted) DBs and BaaS systems, 67 | incl. 68 | RS](https://kinto.readthedocs.org/en/latest/overview.html#comparison) 69 | 70 | ## Software (libraries) of interest 71 | 72 | - 73 | 74 | ## User Feedback 75 | 76 | - [IRC, 2015-02](IRC,_2015-02 "wikilink") 77 | 78 | ## Wiki TODOs 79 | 80 | - Create structure for [Main Page](Main_Page "wikilink") 81 | - ~~Use nicer, one-line IRC notifications (not the RSS feed)~~ 82 | - ~~Add syntax highlighting, e.g. via 83 | ~~ 84 | - ~~Add topnav header to wiki template (same as website, forums)~~ 85 | 86 | ## Random 87 | 88 | - ["Winning back the Open 89 | Web"](http://buytaert.net/winning-back-the-open-web) - Dries 90 | Buytaert thinks that per-user storage is the next big step 91 | -------------------------------------------------------------------------------- /wiki/protocol.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Protocol 3 | parent: Wiki 4 | --- 5 | 6 | This page was moved from the old wiki and is in the process of being revised. 7 | 8 | ## History 9 | 10 | The first draft of the remoteStorage protocol was originally developed by Michiel B. de Jong as part of the [Unhosted](https://unhosted.org) project in 2011 and has been published at a [W3C Community Group](https://www.w3.org/community/unhosted/), which has since been deprecated. Since December 2012, the protocol specification drafts [are published as Internet Drafts at the IETF](https://datatracker.ietf.org/doc/draft-dejong-remotestorage/). 11 | 12 | ## Process 13 | 14 | Every 6 months (max. 185 days) a new draft version is published, incorporating feedback and contributions from developers, providers and users. All discussion and spec development is done in open collaboration on [the public GitHub repository](https://github.com/remotestorage/spec). Everyone is invited to open new GitHub issues and/or pull requests with their questions, feedback, and changes. 15 | --------------------------------------------------------------------------------