{"id":13747962,"url":"https://github.com/gritzko/swarm","last_synced_at":"2026-02-19T23:03:22.154Z","repository":{"id":49405535,"uuid":"9654171","full_name":"gritzko/swarm","owner":"gritzko","description":"JavaScript replicated model (M of MVC) library","archived":false,"fork":false,"pushed_at":"2024-10-29T14:02:46.000Z","size":4200,"stargazers_count":2679,"open_issues_count":30,"forks_count":99,"subscribers_count":94,"default_branch":"master","last_synced_at":"2026-01-26T02:13:19.866Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://swarmdb.net/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gritzko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-04-24T17:58:24.000Z","updated_at":"2026-01-19T13:30:06.000Z","dependencies_parsed_at":"2024-11-15T00:11:16.283Z","dependency_job_id":null,"html_url":"https://github.com/gritzko/swarm","commit_stats":{"total_commits":1059,"total_committers":12,"mean_commits":88.25,"dds":0.2540132200188857,"last_synced_commit":"acb7ec165aabf1c8683af4502cea6b18f8fcbcd0"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/gritzko/swarm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gritzko%2Fswarm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gritzko%2Fswarm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gritzko%2Fswarm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gritzko%2Fswarm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gritzko","download_url":"https://codeload.github.com/gritzko/swarm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gritzko%2Fswarm/sbom","scorecard":{"id":445927,"data":{"date":"2025-08-11","repo":{"name":"github.com/gritzko/swarm","commit":"acb7ec165aabf1c8683af4502cea6b18f8fcbcd0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"88 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-8w4h-3cm3-2pm2","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-rq8g-5pc5-wrhr","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-hr2v-3952-633q","Warn: Project is vulnerable to: GHSA-h6ch-v84p-w6p9","Warn: Project is vulnerable to: GHSA-ff7x-qrg7-qggm","Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-xf7w-r453-m56c","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-44pw-h2cw-w3vq","Warn: Project is vulnerable to: GHSA-jp4x-w63m-7wgm","Warn: Project is vulnerable to: GHSA-c429-5p7v-vgjp","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-4xcv-9jjx-gfj3","Warn: Project is vulnerable to: GHSA-f9cm-qmx5-m98h","Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-3mpr-hq3p-49h9","Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9","Warn: Project is vulnerable to: GHSA-8hfj-j24r-96c4","Warn: Project is vulnerable to: GHSA-wc69-rhjr-hc9g","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-6394-6h9h-cfjg","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-6g33-f262-xjp4","Warn: Project is vulnerable to: GHSA-mvjj-gqq2-p4hw","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-jv35-xqg7-f92r","Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp","Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr","Warn: Project is vulnerable to: GHSA-2m39-62fm-q8r3","Warn: Project is vulnerable to: GHSA-mf6x-7mm4-x2g7","Warn: Project is vulnerable to: GHSA-j44m-qm6p-hp7m","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-38fc-wpqx-33j7","Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v","Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx","Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T06:42:55.536Z","repository_id":49405535,"created_at":"2025-08-19T06:42:55.536Z","updated_at":"2025-08-19T06:42:55.536Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29636040,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T22:32:43.237Z","status":"ssl_error","status_checked_at":"2026-02-19T22:32:38.330Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T07:00:31.204Z","updated_at":"2026-02-19T23:03:22.131Z","avatar_url":"https://github.com/gritzko.png","language":"JavaScript","funding_links":[],"categories":["Awesome React","JavaScript","Implementations","Server","📦 Legacy \u0026 Inactive Projects"],"sub_categories":["Tools","Databases and Logs","JavaScript"],"readme":"This code is historical. See [RDX C](https://github.com/gritzko/librdx) or [RDX Go](https://github.com/drpcorg/chotki/rdx) for the new generation of the technology. No JavaScript impl yet. Maybe you can help, please use [Issues](https://github.com/gritzko/librdx/issues).\n\n# Swarm 2.0 real-time sync [![BuildStatus](https://travis-ci.org/gritzko/swarm.svg?branch=master)](https://travis-ci.org/gritzko/swarm)\n\n\u003cimg align=\"right\" width=\"400\" src=\"https://i.imgur.com/hqGwft1.png\"\u003e\n\nSwarm.js is a JavaScript client for the Swarm database.\nSwarm is like \"git for data\" except it's real-time and never has a merge conflict.\nSwarm is based on [Replicated Object Notation](http://github.com/gritzko/ron) (RON), a distributed live data format.\nIn turn, RON is based on [Conflict-free Replicated Data Types](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) (CRDTs), a new math apparatus for distributed data.\n\nLike git, Swarm gives you a replica of your data which is as good as any other replica.\nYou can read, you can write, you can see it updated by others.\nConcurrent changes merge automatically.\nOffline replicas re-sync on re-connection.\nAll data is cached.\n\nAPI-wise, Swarm is an object graph, although the API may depend on a particular mapper.\nStill, any API is a \"view\" of the system.\nThe ground truth is RON.\n\nSwarm picks its trade-offs in a rather opinionated way.\nIt fits the world of abundant storage and unreliable wireless connections.\n\nSwarm.js is isomorphic and is perfect for implementing synchronization, collaboration or continuity features in Web and [mobile](https://facebook.github.io/react-native/) apps.\nSwarm works for:\n\n* vanilla client-server sync,\n* real-time collaboration,\n* continuity,\n* offline work,\n* and other sync-related scenarios.\n\nUnlike Firebase and others, you may run your own swarm server.\nIf you understand how CRDT works, then you may [implement](https://github.com/gritzko/ron/tree/master/rdt) your own data types.\nFree-as-in-freedom (MIT).\n\n## Table of contents:\n\n* [Intro](#swarm-20-real-time-sync)\n* [Demos](#demos)\n* [Setup](#setup)\n* [CRDT implementations](#crdt-implementations)\n* [API](#api)\n* [GraphQL](#graphql)\n* [Using with React](#using-with-react)\n* [FAQ](#faq)\n* [TODO](#todo)\n* [Contributing](#contributing)\n* [Contacts](#contacts)\n\n## Demos\n\nSee our demos: \n\n* \"Mice\" application - [demo](https://olebedev.github.io/mice), [source](https://github.com/olebedev/mice) code.\n  \n  \u003cdetails open=\"open\"\u003e\u003csummary\u003e\u003cb\u003ePreview\u003c/b\u003e\u003c/summary\u003e\n    \u003cimg src=\"https://i.imgur.com/tv8EITG.gif\" width=\"600\"\u003e\n  \u003c/details\u003e\n  \n  \n* Chat application - demos for [webkit-backed browsers](https://olebedev.github.io/chat), [iOS](https://itunes.apple.com/us/app/swarmdb-demo/id1366936026?ls=1\u0026mt=8), [Android](https://play.google.com/apps/testing/com.swarmchat) and the [source](https://github.com/olebedev/chat) code\n\n  \u003cdetails\u003e\u003csummary\u003e\u003cb\u003ePreview\u003c/b\u003e\u003c/summary\u003e\n    \u003cimg src=\"https://i.imgur.com/9kZDBdG.gif\" width=\"900\"\u003e\n  \u003c/details\u003e\n\n\n* Todo application, based on the world-famous TodoMVC - [demo](http://olebedev.github.io/todo/) and [source](https://github.com/olebedev/todo)\n\n  \u003cdetails\u003e\u003csummary\u003e\u003cb\u003ePreview\u003c/b\u003e\u003c/summary\u003e\n    \u003cimg src=\"https://i.imgur.com/TQKTkf2.gif\" width=\"600\"\u003e\n  \u003c/details\u003e\n\nEvery app perfectly works offline.\n\n\n## Setup\n\nA basic Swarm server implementation is available as a docker image. First, please make sure that you have the docker installed. Then, run the container:\n\n```bash\n$ docker run -d --name swarmdb -p 31415:31415 -v `pwd`:/var/lib/swarm olebedev/swarmdb\n```\n\nOnce a Swarm server is listening incoming connections on `ws://0.0.0.0:31415`, we can initiate connections.\nBut let's suppose that we can't talk RON over raw WebSocket.\n\nThen, let's setup a JavaScript client project:\n\n```bash\n$ mkdir ./myapp\n$ cd ./myapp\n$ yarn add @swarm/db graphql-tag\n```\n\nNow we can initialize a client instance and connect it to the running server.\n\n```javascript\nimport gql from 'graphql-tag';\nimport SwarmDB, { LocalStorage } from '@swarm/db';\n\nconst swarm = new SwarmDB({\n  storage: new LocalStorage(),\n  upstream: 'ws://0.0.0.0:31415',\n  db: { name: 'default' }\n});\n\n// And then subscribe to live data.\nconst query = gql`\n  subscription ChatsList($from: Int = 0, $to: Int = 100, $uid: UUID!) {\n    chats @node(id: \"chats\") {\n      version\n      length\n      list: id @slice(begin: $from, end: $to) {\n        title\n        picture\n        private\n      }\n    }\n    user @node(id: $uid) {\n      id\n      version\n      username\n      avatar\n    }\n  }\n`\n\nconst variables = { from: 0, to: 20, uid: 'X8Kq%~github' }\nswarm.execute({ query, variables }, ({ data, error, off }) =\u003e {\n  // handle updates \n  // or stop receiving updates via call `off()`\n})\n```\n\n## CRDT implementations\n\n* [x] [LWW](packages/rdt/lww.js), a last-write-wins replicated data type that may host a variety of user-land data types, like: a dictionary, a simple 1D array (no splice, no index shifts). This LWW employs client-side logical timestamps to decide which write wins, on a field-by-field basis. That is similar to e.g. Cassandra LWW.\n\n* [x] [Set](packages/rdt/set.js), fully commutative, ordered, with tombstones set. You can either add or remove an atom. \n\n* [ ] [RGA](#), a replicated growable array.\n* [ ] [Counter](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#PN-Counter_(Positive-Negative_Counter)), a positive-negative counter.\n\n## API\n\n#### `constructor(options: Options): SwarmDB`\n\nCreates a new Swarm instance. \nFetches the metadata from the server, saves it locally, sets the replica up (async, see [`ensure()`](#ensure-promisevoid) method).  \n\nParameters:\n\n* `options` - an object with properties:\n\n\t* `storage` - a storage interface implementation, required. There are tree implementations: [in-memory](https://github.com/gritzko/swarm/blob/master/packages/client/src/index.js#L29), [localStorage](https://github.com/gritzko/swarm/blob/master/packages/client/src/index.js#L29)(web) and [AsyncStorage](https://github.com/gritzko/swarm/blob/master/packages/client/src/asyncStorage.js#L7)(ReactNative).\n\t* `upstream` - URL string, e.g. `'wss://the.host.com'`, required\n\t* `db` - an object, required\n\t\t* `name` - A database name, required\n\t\t* `auth` - a JWT, makes sense if auth mode enabled at the server, ignored otherwise\n\nExample:\n\n```javascript\nconst swarm = new SwarmDB({\n  storage: new InMemory(),\n  upstream: 'wss://example.com',\n  db: { name: 'default' }\n});\n```\n\n#### `execute(request: Request, cbk\u003cT\u003e: (Response\u003cT\u003e) =\u003e void ): Promise\u003c{ ok: boolean, off: () =\u003e void }\u003e`\n\nFetch data by a [GraphQL query](http://graphql.org)([see below](#graphql)).\n\nParameters:\n\n* `request` - an object with properties:\n\t*  `query`  - GraphQL AST\n\t*  `variables` - arguments for GraphQL statement\n* `cbk` - a callback function which accepts `Response\u003cT\u003e` - object with properties:\n\t* `data` - `T`\n\t* `off` - a function which cancels a subscription, may be _undefined_ for mutations and static queries\n\t* `error` - an error if any\n\nExample:\n\n```javascript\nconst query = gql`\nsubscription GetChats($from: Int!, $to: Int!) { \n  chats @node(id: \"chats\") { \n    length\n    list: id @slice(begin: $from, end: $to) {\n      title\n    }\n  } \n}`\n\nconst variables = { from: 0, to: 20 }\nswarm.execute({ query, variables }, ({ data, error, off }) =\u003e {\n  // handle updates \n  // or stop receiving updates via call `off()`\n})\n\n```\n\n#### `close(): Promise\u003cvoid\u003e`\n\nReturns a _Promise_ which will be resolved when the replica is closed(websocket closed and the state is written to the storage).\n\n#### `ensure(): Promise\u003cvoid\u003e`\n\nReturns a _Promise_ which will be resolved when the replica is initialized and ready to use. \n\n#### `open(): void`\n\n(Re)Opens websocket connection to a database server.  \n\n#### `uuid(): UUID`\n\nReturns a new timestamp-based UUID.\n\n#### `uuid.local()`\n\nUse local UUIDs for nodes you don't want to send to the server.\nExample:\n\n```javascript\nconst dashboard = swarm.uuid().local() // a local uuid works only for the current instance. \n```\n\nNote that a local object can reference a shared object, but not the other way round.\nPlease take a look at [todo](https://github.com/olebedev/todo/blob/master/src/graphql.js#L50) to see at fully working example of using local UUIDs for local state management.\n\n\n## GraphQL\n\nSwarm has a GraphQL API on the client side.\nServer-client communication employs RON (state, ops, patches).\n\nSwarm offers GraphQL as a *schema-less* interface to fetch and modify your data, with basic mutations operations for specific CRDTs, and with several additional directives(see below).\nGraphQL is used to describe(declare) the shape of the requested data tree. \n\nKey features:\n\n* data reactivity (full or partial)\n* (sub)documents/(sub)collections as first-class citizens\n* every object has a globally-unique Swarm UUID (see teh @node directive)\n\n\n### Basic primitives and conventions\n\n`UUID` - is a [Swarm UUID](https://github.com/olebedev/swarm/blob/master/packages/ron-uuid/src/index.js#L6) or a string representation of an `UUID`.  \n\n```graphql\nscalar UUID\n```\n\n`Atom` - a scalar (a union of scalar types).  \n\n```graphql\nunion Atom = String | Int | Float | Boolean | UUID\n```\n\n`Node` - is an interface of CRDT which presented as a key/value object where a value is a union of `Atom | Node | [Node]`. Internally, each objects JS prototype regardless its type has `id`, `type` and `version` fields. Additionally, the `set` type has `length` field, and `lww` type can also has `length` in case if all the user-land field keys are _numbers_(say, index of array). There are no native JavaScript arrays by default, they can be produced by directives(see below). \n\n```graphql\ninterface Node {\n  id: String!\n  type: String!\n  version: String!\n  length: Int # only for array-like objects\n  # ... various of keys and values\n}\n```\n\n`Payload` - is a flat key/value object. Where keys are strings and values are `Atom`s. \n\n```graphql\ninterface Payload {\n  # ... various of keys and values\n}\n```\n\n### Queries \u0026 Subscriptions\n\nBoth of these two root fields serve to declare the tree you intend to get as a result of the execution. There is nothing special except that you don't need to define schema.\n\nExample. Let's subscribe to the last 100 users from the `users` collection.\n\n```javascript\nconst query = gql`\nsubscription Users($from: Int = 0, $to: Int = 100) { \n  users @node(id: \"users\") @slice(begin: $from, end: $to) {\n    username\n    picture\n  } \n}`\n\nswarm.execute({ query }, ({ data, error, off }) =\u003e {\n  // handle updates \n  console.log(data.users.list) // prints array of users\n})\n```\nThe difference between _subscription_ and _query_ is a data reactivity, see more details [here](#live--static).\n\n### Mutations\n\nMutations are strictly defined and depend on CRDTs which are implemented. All of them listed below.\n\n```graphql\ntype Mutation {\n  # for LWW\n  set(id: UUID!, payload: Payload!): Bool\n  \n  # for Set\n  add(id: UUID!, value: Atom): Bool\n  remove(id: UUID!, value: Atom): Bool\n}\n```\n\nNote that an error will be raised in case of type mismatch.\n\nExample. Suppose we have to add subdocument into user profile. For that we need to have an identifier(`UUID`) for new node, then we can put it into the parent document.\n\n```javascript\n// define mutation\nconst addSettings = gql`\n  mutation AddSettings(\n    $uid: UUID!, \n    $patch: Payload!, \n    $settingsID: UUID!, \n    $settings: Payload!\n  ) {q\n    patchUserObject: set($uid, $patch)\n    createSettings: set($settingsID, $settings)\n  }\n`\n\n// create a node ID\nconst settingsID = swarm.uuid();\n\n// define arguments\nconst variables = {\n  uid: 'X8Kq%~github', // user ID\n  patch: { settings: settingsID }, // put new node ref into new field\n  settingsID,\n  settings: { premium: true }, // a settings object to add\n}\n\n// run the mutation\nawait swarm.execute({ query: addSettings, variables }, resp =\u003e {\n  console.log(resp.data) // will print { patchUserObject: true, createSettings: true }\n})\n// swarm.execute resolves Promise after all mutations were applied\n```\n\n### Directives\n\nHere are the directives defined in Swarm GraphQL runtime, in addition to [default](http://graphql.org/learn/queries/#directives) ones. \n\n#### @node\n\n```graphql\ndirective @node(id: UUID!) on FIELD\n```\n\nUsed to define which node of Swarm graph should be unwrapped.\nCan be missed if the field already contains a UUID itself(for nested objects). \n\n```graphql\ndirective @node(id: UUID!) on FIELD\n# example\nsubscription {\n  user @node(id: \"X8Kq%~github\") {\n    version\n    username\n  }\n  dashboard @node(id: \"dash%~local\") { # fetch locally presented node\n    screen\n    tasks @node(id: tasks) {\n      length\n      list: id @slice(begin: 0) {\n        id\n        title\n        progress\n      }\n    }\n  }\n}\n```\n\n\n#### @live \u0026 @static\n\n```graphql\ndirective @static on FIELD\ndirective @live on FIELD\n```\n\nBoth add an ability to define a [partial reactivity](https://youtu.be/BSw05rJaCpA). All the nodes in the _subscription_ root field are reactive along with all the nodes in the _query_ root field are static. _Subscription_ and _query_ root field are interchangeable. So, it's up to developer which root field will be used, depends on how many nodes in a tree should be static or reactive. \n\nOnce a static node was fetched from the server and cached, it will be returned from the cache without network activity. \n\n```graphql\n# fetch user once and cache for further queries\n# and install subscription to notificatoins\nsubscription {\n  user @node(id: \"X8Kq%~github\") @static {\n    version\n    username\n    notifications @slice(begin: 0) {\n      title\n      read\n    }\n  }\n}\n\n# and the same example with query root field\nquery {\n  user @node(id: \"X8Kq%~github\") {\n    version\n    username\n    notifications @slice(begin: 0) @live {\n      title\n      read\n    }\n  }\n}\n```\n\n\n#### @weak\n\n```graphql\ndirective @weak on FIELD\n```\n\nAdds more control to data flow management. By default, Swarm tries to fetch a node from the server if there is none presented in the local cache. So, _query_ or _subscription_ can block an application if there is no open connection. This directive tells the runtime to call back with `null`(don't wait for the server response) if the node is not presented in the local cache yet. Useful for offline work. \n\n\n```graphql\n#example \nquery {\n  user @node(id: \"X8Kq%~github\") @live @weak {\n    username\n    version\n  }\n}\n```\n\nYou can identify if the node doesn't exist in the system(the server) by checking `version` field. It contains `'0'`  in `version` field.\n\n#### @slice \u0026 @reverse\n\n```graphql\ndirective @slice(offset: Int!, limit: Int) on FIELD\ndirective @reverse on FIELD\n```\n\nThese directives are for array-like objects/nodes. They work exactly like array methods in JavaScript. In fact, they call these methods.  But before calling the method the runtime tries to cast the object/node to an array via `Array.prototype.slice.call(node)`. \n\nFor example, let's subscribe to nodes changes with UUID `messages`, meta data of the set(id, version, length) and the first message with an author.\n\n```graphql\nsubscription {\n  messages @node(id: \"messages\") {\n    version\n    length\n    list: id @reverse @slice(begin: 0, end: 1) {\n      id\n      version\n      text\n      author {\n        id\n        username\n        picture\n      }\n    }\n  }\n}\n```\n\n#### @date\n\n```graphql\ndirective @date on FIELD\n```\nThis directive casts the value into the _Date_ Javascript object, works only for Swarm UUID values or string representations. \n\n```graphql\n# example\nquery {\n  user @node(id: \"X8Kq%~github\") {\n    lastTimeModified: version @date\n    username\n  }\n}\n```\n\n#### @uuid\n\n```graphql\ndirective @uuid on FIELD\n```\nThis directive casts a string value into the UUID object, works only for string representations. \n\n\u003e Notice. Priority of execution of directives from the first to the last.\n\n## Using with [React](https://reactjs.org/)\n\n### `\u003cGraphQL swarm query variables mutations children/\u003e`\n\nIt's a React component which uses the [render prop pattern](https://reactjs.org/docs/render-props.html) to get and/or update Swarm live-data. It calls `children` prop function with the result of query - `data`, bound `mutations`, `error`(if any) and and function `uuid` to create new UUIDs. \n\n#### Props\n\n* `swarm`: The single Swarm instance in your application. In case if  you don't use [`\u003cProvider /\u003e`](#provider-swarm-children) or intend to use another Swarm instance.\n* `query`: A GraphQL query/subscription wrapped with `gql` function.\n* `variables`: Variables object of the query/subscription.\n* `mutations`: An object of mutations to bind it with Swarm instance. \n* `children`: A prop function which returns a component subtree.\n  \n  Children prop will be called with an object which contains fields:\n  \n  * `data`: A result of query/subscription execution. May be null if there is no result yet.\n  * `mutations`: An object with the same shape as a mutation prop but bound to the Swarm instance and ready to call with variables or without. \n  * `error`: An error of operations if any.\n  * `uuid`: [A function](#uuid-uuid) which returns a new UUID. Null if the swarm instance is not initialized yet(see [`ensure()`](#ensure-promisevoid)).\n\n  \n  \nExample:\n\n```javascript\nimport gql from \"graphql-tag\";\nimport { GraphQL } from \"swarm-react\";\n\nconst query = gql`\n  subscription List($id: UUID!) {\n    items @node(id: $id) @slice(begin: 0) {\n      title\n    }\n  }\n`;\n\nconst create = gql`\n  mutation AddItem($listId: UUID!, $id: UUID!, $payload: Payload!) {\n    created: set(id: $id, payload: $payload)\n    added: add(id: $listId, value: $id)\n  }\n`;\n\nconst List = ({ id }) =\u003e (\n  \u003cGraphQL query={query} variables={{ id }} mutations={{ create }}\u003e\n    {({ data, mutations, error, uuid }) =\u003e {\n      if (error) return \u003cRenderError error={error} /\u003e;\n      return (\n        \u003cMyComponent\n          data={data ? data.items : []}\n          onCreate={payload =\u003e\n            uuid \u0026\u0026\n            mutations.create({\n              id: uuid(),\n              listId: id,\n              payload\n            })\n          }\n        /\u003e\n      );\n    }}\n  \u003c/GraphQL\u003e\n);\n\nexport default List;\n```\n\n### `\u003cProvider swarm children/\u003e`\n\nMakes the Swarm instance available to the [`\u003cGraphQL /\u003e`](#) components in the component hierarchy below without passing swarm instance directly to each of them. \n\n#### Props\n\n* `swarm`: The single Swarm instance in your application.\n* `children`: The root React element of your component hierarchy.\n\nExample:\n\n```javascript\nimport { Provider } from '@swarm/react';\n\n// ...\n\nReactDOM.render(\n  \u003cProvider swarm={swarm}\u003e\n    \u003cMyRootComponent /\u003e\n  \u003c/Provider\u003e,\n  rootEl\n)\n```\n\n## FAQ\n\n\u003e What is the state of the project?\n\nThe underlying layer - RON is stable and APIs are frozen. The client and the server are ready for building prototypes and kind of MVPs but not production ready yet. \n\n\u003e How do I manage collections of documents in Swarm?\n\nFor documents use `LWW` type and for collections use `Set` type.\n\nSwarm is a JSON graph. Very much like in Firebase or MongoDB - document/collection-based approach. The key difference is thet you can put references into the graph, so, no need to denormalize your data and keep your data as flat as possible. Opposite to it, shape your data as deep as you want. \n\n\u003e Why GraphQL?\n\nIt's a declarative paradigm approach. It allows shaping resulting data whatever you want, without additional transformations/joins in user space. Also, it's a good fit too due to graph nature of Swarm data.\n\n## TODO\n\n* [ ] full GraphQL support - schemas, client-side validation \n* [ ] authentication and access control\n* [ ] connector for Postgres and others\n* [ ] continuous queries(a.k.a \"live queries\")\n\n## Contributing\n\nTODO\n\n## Contacts\n\n* Victor Grishchenko https://github.com/gritzko\n* Oleg Lebedev https://github.com/olebedev\n\nFollow Swarm on [twitter](https://twitter.com/swarmsync) and read our [blog](http://swarmdb.github.io/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgritzko%2Fswarm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgritzko%2Fswarm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgritzko%2Fswarm/lists"}