{"id":17247654,"url":"https://github.com/joshdata/draft.cloud","last_synced_at":"2025-03-26T05:41:38.169Z","repository":{"id":66126355,"uuid":"83040357","full_name":"JoshData/draft.cloud","owner":"JoshData","description":null,"archived":false,"fork":false,"pushed_at":"2024-06-13T04:22:42.000Z","size":804,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"primary","last_synced_at":"2025-01-31T07:17:02.907Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JoshData.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2017-02-24T12:42:54.000Z","updated_at":"2020-07-05T17:39:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"237816eb-6678-4371-bad8-95c48ef30cc5","html_url":"https://github.com/JoshData/draft.cloud","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoshData%2Fdraft.cloud","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoshData%2Fdraft.cloud/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoshData%2Fdraft.cloud/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoshData%2Fdraft.cloud/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JoshData","download_url":"https://codeload.github.com/JoshData/draft.cloud/tar.gz/refs/heads/primary","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245598294,"owners_count":20641882,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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-10-15T06:38:32.216Z","updated_at":"2025-03-26T05:41:38.150Z","avatar_url":"https://github.com/JoshData.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Draft.Cloud\n\n(This project is not open source.)\n\n## Installation\n\nInstall node and packages:\n\n\tcd ~ # go to home directory, nvm install gets confused if there's a .git dir\n\tcurl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.3/install.sh | bash\n\tnvm install $(nvm ls-remote | tail -1)\n\n\tcd draft.cloud\n\tnpm install\n\nStart it up:\n\n\t./build.sh\n\tnode index.js --allow_anonymous_user_creation\n\nTesting using the command line and our helper script that makes HTTP REST API calls. Start by making a new user by calling the `/users` API with a POST request:\n\n\tbackend/req POST '{ \"name\": \"user1\" }' /users\n\n`backend/req` is just a helper script that forms an API request using `curl` (so make sure you have `curl` installed). In this first example it makes an HTTP POST request to `http://localhost:8000/api/v1/users` with `{ \"name\": \"user1\" }` as the POST request body.\n\nThe response will contain a special HTTP header named `X-Api-Key` and the body will be JSON containing information about the newly created user:\n\n\t...\n\tX-Api-Key: bbd5c77f-14ad-4cf4-ac25-fd3e3abecd5c.s2OkOblxRAyvR4sOGmE2JjQRRH/XmcHZ.0\n\t...\n\n\t{\n\t  \"id\": \"dfb05874-5081-4d16-86d3-80c463cc8277\",\n\t  \"name\": \"user1\",\n\t  \"created\": \"2020-02-16T13:34:39.687Z\",\n\t  \"api_urls\": {\n\t    \"profile\": \"http://localhost:8000/api/v1/users/dfb05874-5081-4d16-86d3-80c463cc8277\",\n\t    \"documents\": \"http://localhost:8000/api/v1/documents/dfb05874-5081-4d16-86d3-80c463cc8277\"\n\t  }\n\t}\n\nEach user has an `id` which is a UUID and a unique `name` which is initialized to a random string if it is not provided in the POST request to create the user.\n\nThe user's API key is returned in the `X-Api-Key` HTTP header which you'll see in the response output. Copy it into an environment variable:\n\t\n\texport API_KEY=bbd5c77f-14ad-4cf4-ac25-fd3e3abecd5c.s2OkOblxRAyvR4sOGmE2JjQRRH/XmcHZ.0\n\nThen create a document:\n\n\tbackend/req POST '{ \"name\": \"document1\" }' /documents/me\n\n`me` is an alias for your own user `id`.\n\nOutput:\n\n\t...\n\n\t{\n\t  \"id\": \"ff5a3057-b112-4d05-9de3-9b1c91dec3fa\",\n\t  \"name\": \"document1\",\n\t  \"created\": \"2020-02-16T13:49:46.257Z\",\n\t  \"public_access_level\": \"NONE\",\n\t  \"owner\": {\n\t    \"name\": \"user1\",\n\t    ...\n\t  },\n\t  \"userdata\": {},\n\t  \"api_urls\": {\n\t\t...\n\t    \"debugger\": \"http://localhost:8000/api/v1/documents/468604fa-f5cc-44b7-9477-d2c9bd9c7eef/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/debug\"\n\t  },\n\t  \"web_urls\": {\n\t    \"document\": \"http://localhost:8000/edit/user1/document1\"\n\t  }\n\t}\n\nLike users, each document has an `id` which is a UUID and a `name` which is unique across the user's documents. The name is initialized to a random string if it is not provided in the POST request to create the document.\n\nNeed to get this information again? List all of your documents:\n\n\tbackend/req GET '' /documents/me\n\nNow you can edit this document in three ways...\n\n### Using the Draft.Cloud API\n\n#### Reading and writing document content\n\nThe Draft.Cloud API has two methods to update a document: PUTing an updated document or PATCHing a document with a diff in the form of a JOT operation.\n\nFirst, let's get the current content of the document. Use a GET request and the `id` of the document returned in the previous API call:\n\n\tbackend/req GET '' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nIn the HTTP response headers you'll get the `Revision-Id` of the documentation's current revision and in the HTTP response body you will get a JSON value with the document's content:\n\n\tRevision-Id: singularity\n\t...\n\tnull\n\nAll Draft.Cloud documents are JSON data structures. All new documents start off holding just the value `null`, and the first `Revision-Id` is always `singularity`.\n\nNow updated it to a text value using a PUT request:\n\n\tbackend/req PUT '\"This is a JSON string value.\"' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nNote that the request body `\"This is a JSON string value.\"` quotes the text because you are submitting a JSON value, not plain text.\n\nThe response will have HTTP status code 201 and give information about the new revision of the document:\n\n\t{\n\t  \"created\": \"2020-06-13T12:27:12.989Z\",\n\t  \"id\": \"57cf779f-ac4a-411f-8076-615c9c558b4b\",\n\t  \"author\": {\n\t    ...\n\t    \"name\": \"user1\"\n\t  },\n\t  \"userdata\": null,\n\t  \"status\": \"committed\",\n\t  \"op\": {\n\t    \"_ver\": 1,\n\t    \"_type\": \"values.SET\",\n\t    \"value\": \"This is a JSON string value.\"\n\t  }\n\t}\n\nIf you call the API with the exact same request again, you'll get a response with a 200 status code and a body containing\n\n\tno change\n\nbecause you haven't modified the document. Try again but with \"JSON\" removed from the text:\n\n\tbackend/req PUT '\"This is a string value.\"' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nThe response will show a change starting at character 10 which is automatically computed for you:\n\n\t{\n\t  \"created\": \"2020-06-13T12:32:00.353Z\",\n\t  \"id\": \"605f5561-c69c-4597-babe-ae33c4100d68\",\n\t  ...\n\t  \"op\": {\n\t    \"_ver\": 1,\n\t    \"_type\": \"sequences.PATCH\",\n\t    \"hunks\": [\n\t      {\n\t        \"offset\": 10,\n\t        \"length\": 5,\n\t        \"op\": {\n\t          \"_type\": \"values.SET\",\n\t          \"value\": \"\"\n\t        }\n\t      }\n\t    ]\n\t  }\n\t}\n\nNow you can get the document:\n\n\tbackend/req GET '' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nwhich returns the `Revision-Id` HTTP header and a JSON value in the response body for the current value of the document:\n\n\tRevision-Id: 605f5561-c69c-4597-babe-ae33c4100d68\n\t...\n\t\"This is a string value.\"\n\n#### Working with plain text documents\n\nWhen working with plain text documents, you can use the HTTP Content-Type and Accept headers to simplify. With our helper script, set the `CONTENT_TYPE` environment variable to set the Content-Type header and update the document:\n\n\tCONTENT_TYPE=text/plain backend/req PUT 'This is my document.' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nNote that the double quotes are now gone from the POST body --- you're submitting plain text, not JSON, now. And set the `ACCEPT` environment variable for our helper script to set the Accept HTTP header toget the text back plainly:\n\n\tACCEPT=text/plain backend/req GET '' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nwhich returns\n\n\tRevision-Id: b0ea9d9c-f5f7-4d89-a68e-fb1a8cd590aa\n\t...\n\tThis is my document.\n\nagain, without quotes because this is now plain text, not JSON.\n\n#### Conflict resolution of simultaneous edits\n\nDraft.Cloud automatically resolves conflicts in simultaneous edits when the POST request includes the ID of the revision it last saw in the `Base-Revision-Id` header. Using our helper script, you can set that header by setting the `BASEREV` environment variable.\n\nLet's make two changes. The first change will replace the word `is` with `was`:\n\n\tBASEREV=b0ea9d9c-f5f7-4d89-a68e-fb1a8cd590aa backend/req PUT '\"This was my document.\"' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nThis change is now committed to the document. However, imagine that simultaneously someone else made a different change replacing `document` with `mission`:\n\n\tBASEREV=b0ea9d9c-f5f7-4d89-a68e-fb1a8cd590aa backend/req PUT '\"This is my mission.\"' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\nNote that in this second change, the verb is still `is`!\n\nWill the first API call's change from `is` to `was` be reverted? No, because the `Base-Revision-Id` header was used in the second call. You can get the current value of the document to see:\n\n\tACCEPT=text/plain backend/req GET '' /documents/me/ff5a3057-b112-4d05-9de3-9b1c91dec3fa/content\n\n\tRevision-Id: 3754fe48-cb4c-4a7a-bd74-7e22657840d5\n\t...\n\tThis was my mission.\n\nAlways use `Base-Revision-Id` with `POST` requests to update a document when the document might be edited by concurrent processes or users.\n\n### Using the Draft.Cloud front-end\n\nThe second and third method uses Draft.Cloud's websocket-based browser widgets.\n\nFirst you'll need to set up authentication in your browser. Using a browser extension to add HTTP headers to requests, and add a header named `Authorization` and set its value to your API key from above:\n\n\tAuthorization: bbd5c77f-14ad-4cf4-ac25-fd3e3abecd5c.s2OkOblxRAyvR4sOGmE2JjQRRH/XmcHZ.0\n\nThe output of the earlier command to create the document has a `web_urls` =\u003e `document` value to view the document in your web browser. In the example it is `http://localhost:8000/edit/user1/document1`. Open that URL.\n\n### Using your own front-end\n\nBecause `\u003cscript\u003e` tags and websockets are not limited by the browser's same-origin policy, you can immediately place a Draft.Cloud widget on your own website --- so long as the browser can see the server you launched Draft.Cloud on. Here's a snippet to embed the Draft.Cloud rich text editor on your site:\n\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      \u003cdiv class=\"draftdotcloud-widget\"\n        data-draftdotcloud-widget=\"quill\"\n        data-draftdotcloud-owner=\"user1\"\n        data-draftdotcloud-document=\"document1\"\n        data-draftdotcloud-baseurl=\"http://localhost:8000\"\n        data-draftdotcloud-apikey=\"bbd5c77f-14ad-4cf4-ac25-fd3e3abecd5c.s2OkOblxRAyvR4sOGmE2JjQRRH/XmcHZ.0\"\n        \u003e\u003c/div\u003e\n  \u003c/body\u003e\n    \u003cscript src=\"http://localhost:8000/draftdotcloud.js\"\u003e \u003c/script\u003e\n\u003c/html\u003e\n```\n\nInstead of a `div`, you can also make any `textarea` or `\u003cinput type=text\u003e` a collaborative document:\n\n```html\n\u003ctextarea class=\"draftdotcloud-widget\"\n  data-draftdotcloud-owner=\"joshdata\"\n  data-draftdotcloud-document=\"testdoc\"\n  data-draftdotcloud-baseurl=\"http://localhost:8000\"\n  data-draftdotcloud-apikey=\"7b88ea21-8992-432d-8c8d-50a0a194d007.3t8LKawKXH/V62O+o5hClAXZ8fEZAcOr.0\"\n\u003e\u003c/textarea\u003e\n```\n\nIt is your web application server's responsibility to provision a Draft.Cloud API key for the end user and embed it within the HTML page.\n\n## Deployment\n\nSee the full set of options that you may need to set:\n\n\tnode index.js --help\n\nOptions can be specified in environment variables, on the command-line, or in a configuration file.\n\nYou will likely need to set the `URL` and `DATABASE` settings (and possibly also the `BIND_HOST`, `PORT`, and `TRUST_PROXY` settings) either by setting environment variables, a settings file with NAME=VALUE lines, or using the corresponding command-line arguments described in the help output. The `SECRET_KEY` setting is required to enable login sessions (see [express session](https://www.npmjs.com/package/express-session#secret)).\n\nDefault values are also shown in the help output. The default database is a Sqlite database named `db.sqlite` stored in the current directory.\n\nIf running with a Postgres database you'll need to install the `pg` package:\n\n\tnpm install pg\n\nTo deploy with docker, build the image and run the image like so:\n\n\tdocker build -t draftdotcloud/draftdotcloud-server .\n\tdocker run --rm -p 8000:8000 -e ALLOW_ANONYMOUS_USER_CREATION=1 -e SECRET_KEY=mysecret  -e DATABASE=postgres://host/db draftdotcloud/draftdotcloud-server\n\nIn a regular virtual machine environment, configure nginx and supervisor:\n\n\tsudo ln -sf /home/draftdotcloud/draft.cloud/conf/nginx.conf /etc/nginx/sites-enabled/draftdotcloud\n\tsudo ln -sf /home/draftdotcloud/draft.cloud/conf/supervisor.ini /etc/supervisor/conf.d/draftdotcloud.conf\n\n## Development\n\nRun tests:\n\n\tnpm test\n\nBuild API documentation: See `build.sh`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshdata%2Fdraft.cloud","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshdata%2Fdraft.cloud","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshdata%2Fdraft.cloud/lists"}