diff --git a/README.md b/README.md index c3fe459a..f2f35b2a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Spee.ch -spee.ch provides a user-friendly, custom-designed, image and video hosting site backed by a decentralized network and +spee.ch provides a user-friendly, custom-designed, image and video hosting site backed by a decentralized network and blockchain ([LBRY](https://lbry.tech/)). Via just a small set of config files, you can spin your an entire spee.ch site back up including assets. ![App GIF](https://spee.ch/e/speechgif.gif) @@ -18,56 +18,64 @@ For a closed, custom-hosted and branded example, check out https://lbry.theantim ### Full Instructions #### Get some information ready: - * mysqlusername - * mysqlpassword - * domainname or 'http://localhost:3000' - * speechport = 3000 + +- mysqlusername +- mysqlpassword +- domainname or 'http://localhost:3000' +- speechport = 3000 #### Install and Set Up Dependencies - * Firewall open ports - * 22 - * 80 - * 443 - * 3333 - * 4444 - * [NodeJS](https://nodejs.org) - * [MySQL version 5.7 or higher](https://dev.mysql.com/doc/refman/8.0/en/installing.html) - * mysqlusername or root - * mysqlpassword - * Requires mysql_native_password plugin - ``` - mysql> `ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword';` - ``` - * [lbrynet](https://github.com/lbryio/lbry) daemon - * run this as a service exposing ports 3333 and 4444 - * _note_: once the daemon is running, issue commands in another terminal session (tmux) to retrieve an address for your wallet to recieve 5+ LBC credits (or join us in the [#speech discord channel](https://discord.gg/YjYbwhS) and we will send you a few) - * `./lbrynet commands` gets a list of commands - * `./lbrynet account_balance` gets your balance (initially 0.0) - * `./lbrynet address_list` gets addresses you can use to recieve LBC - * [FFmpeg](https://www.ffmpeg.org/download.html) - * Spee.ch (below) - * pm2 (optional) process manager such as pm2 to run speech server.js - * http proxy server e.g. caddy, nginx, or traefik, to forward 80/443 to speech port 3000 - * _note: even running on http://localhost, you must redirect http or https to port 3000_ +- Firewall open ports + - 22 + - 80 + - 443 + - 3333 + - 4444 +- [NodeJS](https://nodejs.org) +- [MySQL version 5.7 or higher](https://dev.mysql.com/doc/refman/8.0/en/installing.html) + - mysqlusername or root + - mysqlpassword + - Requires mysql_native_password plugin + ``` + mysql> `ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword';` + ``` +- [lbrynet](https://github.com/lbryio/lbry) daemon + - run this as a service exposing ports 3333 and 4444 + - _note_: once the daemon is running, issue commands in another terminal session (tmux) to retrieve an address for your wallet to recieve 5+ LBC credits (or join us in the [#speech discord channel](https://discord.gg/YjYbwhS) and we will send you a few) + - `./lbrynet commands` gets a list of commands + - `./lbrynet account_balance` gets your balance (initially 0.0) + - `./lbrynet address_list` gets addresses you can use to recieve LBC +- [FFmpeg](https://www.ffmpeg.org/download.html) +- Spee.ch (below) +- pm2 (optional) process manager such as pm2 to run speech server.js +- http proxy server e.g. caddy, nginx, or traefik, to forward 80/443 to speech port 3000 + - _note: even running on http://localhost, you must redirect http or https to port 3000_ #### Clone spee.ch - * release version for stable production + +- release version for stable production + ``` $ git clone -b release https://github.com/lbryio/spee.ch.git ``` - * master version for development + +- master version for development + ``` $ git clone https://github.com/lbryio/spee.ch.git ``` - * your own fork for customization -#### Change directory into your project +- your own fork for customization + +#### Change directory into your project + ``` $ cd spee.ch ``` #### Install node dependencies + ``` $ npm install ``` @@ -91,7 +99,8 @@ $ npm run start ``` #### View in browser - * Visit [http://localhost:3000](http://localhost:3000) in your browser + +- Visit [http://localhost:3000](http://localhost:3000) in your browser #### Customize your app @@ -99,34 +108,44 @@ Check out the [customization guide](https://github.com/lbryio/spee.ch/blob/readm #### (optional) add custom components and update the styles - * Create custom components by creating React components in `site/custom/src/` - * Update or override the CSS by changing the files in `site/custom/scss` +- Create custom components by creating React components in `site/custom/src/` +- Update or override the CSS by changing the files in `site/custom/scss` #### (optional) install your own chainquery + Instructions are coming at [lbry-docker] to install your own chainquery instance using docker-compose. This will require 50GB of preferably SSD space and at least 10 minutes to download, possibly much longer. +## Settings + +There are a number of settings available for customizing the behavior of your installation. +_INSERT LINK TO SETTINGS.MD_ + ## API + #### /api/claim/publish method: `POST` example: + ``` curl -F 'name=MyPictureName' -F 'file=@/path/to/myPicture.jpeg' https://spee.ch/api/claim/publish ``` + Parameters: - * `name` (required, must be unique across the instance) - * `file` (required) (must be type .mp4, .jpeg, .jpg, .gif, or .png) - * `nsfw` (optional) - * `license` (optional) - * `title` (optional) - * `description` (optional) - * `thumbnail` URL to thumbnail image, for .mp4 uploads only (optional) - * `channelName` channel to publish too (optional) - * `channelPassword` password for channel to publish too (optional, but required if `channelName` is provided) +- `name` (required, must be unique across the instance) +- `file` (required) (must be type .mp4, .jpeg, .jpg, .gif, or .png) +- `nsfw` (optional) +- `license` (optional) +- `title` (optional) +- `description` (optional) +- `thumbnail` URL to thumbnail image, for .mp4 uploads only (optional) +- `channelName` channel to publish too (optional) +- `channelPassword` password for channel to publish too (optional, but required if `channelName` is provided) response: + ``` { "success": , @@ -150,13 +169,17 @@ response: ``` #### /api/claim/availability/:name + method: `GET` example: + ``` curl https://spee.ch/api/claim/availability/doitlive ``` + response: + ``` { "success": , // `true` if spee.ch successfully checked the claim availability @@ -168,90 +191,98 @@ response: ## Contribute ### Stack -The spee.ch stack is MySQL, Express.js, Node.js, and React.js. Spee.ch also runs `lbrynet` on its server, and it uses the `lbrynet` API to make requests -- such as `publish`, `create_channel`, and `get` -- on the `LBRY` network. -Spee.ch also runs a sync tool, which decodes blocks from the `LBRY` blockchain as they are mined, and stores the information in MySQL. It stores all claims in the `Claims` table, and all channel claims in the `Certificates` table. +The spee.ch stack is MySQL, Express.js, Node.js, and React.js. Spee.ch also runs `lbrynet` on its server, and it uses the `lbrynet` API to make requests -- such as `publish`, `create_channel`, and `get` -- on the `LBRY` network. -* server - * [MySQL](https://www.mysql.com/) - * [express](https://www.npmjs.com/package/express) - * [node](https://nodejs.org/) - * [lbry](https://github.com/lbryio/lbry) - * [FFmpeg](https://www.ffmpeg.org/) -* client - * [react](https://reactjs.org/) - * redux - * sagas - * scss - * handlebars +Spee.ch also runs a sync tool, which decodes blocks from the `LBRY` blockchain as they are mined, and stores the information in MySQL. It stores all claims in the `Claims` table, and all channel claims in the `Certificates` table. +- server + - [MySQL](https://www.mysql.com/) + - [express](https://www.npmjs.com/package/express) + - [node](https://nodejs.org/) + - [lbry](https://github.com/lbryio/lbry) + - [FFmpeg](https://www.ffmpeg.org/) +- client + - [react](https://reactjs.org/) + - redux + - sagas + - scss + - handlebars ### Architecture -* `cli/` contains the code for the CLI tool. Running the tool will create `.json` config files and place them in the `site/config/` folder - * `configure.js` is the entry point for the CLI tool - * `cli/defaults/` holds default config files - * `cli/questions/` holds the questions that the CLI tool asks to build the config files -* `client/` contains all of the client code - * The client side of spee.ch uses `React` and `Redux` - * `client/src/index.js` is the entry point for the client side js. It checks for preloaded state, creates the store, and places the `` component in the document. - * `client/src/app.js` holds the `` component, which contains the routes for `react-router-dom` - * `client/src/` contains all of the JSX code for the app. When the app is built, the content of this folder is transpiled into the `client/build/` folder. - * The Redux code is broken up into `actions/` `reducers/` and `selectors/` - * The React components are broken up into `containers/` (components that pull props directly from the Redux store), `components/` ('dumb' components), and `pages/` - * spee.ch also uses sagas which are in the `sagas/` folders and `channels/` - * `client/scss/` contains the CSS for the project - * +- `cli/` contains the code for the CLI tool. Running the tool will create `.json` config files and place them in the `site/config/` folder -* `site/custom` is a folder which can be used to override the default components in `client/` - * The folder structure mimics that of the `client/` folder - * to customize spee.ch, place your own components and scss in the `site/custom/src/` and `site/custom/scss` folders. + - `configure.js` is the entry point for the CLI tool + - `cli/defaults/` holds default config files + - `cli/questions/` holds the questions that the CLI tool asks to build the config files -* `server/` contains all of the server code - * `index.js` is the entry point for the server. It creates the [express app](https://expressjs.com/), requires the routes, syncs the database, and starts the server listening on the `PORT` designated in the config files. - * `server/routes/` contains all of the routes for the express app - * `server/controllers/` contains all of the controllers for all of the routes - * `server/models/` contains all of the models which the app uses to interact with the `MySQL` database. - * Spee.ch uses the [sequelize](http://docs.sequelizejs.com/) ORM for communicating with the database. +- `client/` contains all of the client code -* `tests/` holds the end-to-end tests for this project - * Spee.ch uses `mocha` with the `chai` assertion library - * unit tests are located inside the project in-line with the files being tested and are designated with a `xxxx.test.js` file name + - The client side of spee.ch uses `React` and `Redux` + - `client/src/index.js` is the entry point for the client side js. It checks for preloaded state, creates the store, and places the `` component in the document. + - `client/src/app.js` holds the `` component, which contains the routes for `react-router-dom` + - `client/src/` contains all of the JSX code for the app. When the app is built, the content of this folder is transpiled into the `client/build/` folder. + - The Redux code is broken up into `actions/` `reducers/` and `selectors/` + - The React components are broken up into `containers/` (components that pull props directly from the Redux store), `components/` ('dumb' components), and `pages/` + - spee.ch also uses sagas which are in the `sagas/` folders and `channels/` + - `client/scss/` contains the CSS for the project \* + +- `site/custom` is a folder which can be used to override the default components in `client/` + + - The folder structure mimics that of the `client/` folder + - to customize spee.ch, place your own components and scss in the `site/custom/src/` and `site/custom/scss` folders. + +- `server/` contains all of the server code + + - `index.js` is the entry point for the server. It creates the [express app](https://expressjs.com/), requires the routes, syncs the database, and starts the server listening on the `PORT` designated in the config files. + - `server/routes/` contains all of the routes for the express app + - `server/controllers/` contains all of the controllers for all of the routes + - `server/models/` contains all of the models which the app uses to interact with the `MySQL` database. + - Spee.ch uses the [sequelize](http://docs.sequelizejs.com/) ORM for communicating with the database. + +- `tests/` holds the end-to-end tests for this project + - Spee.ch uses `mocha` with the `chai` assertion library + - unit tests are located inside the project in-line with the files being tested and are designated with a `xxxx.test.js` file name ### Tests -* This package uses `mocha` with `chai` for testing. -* Before running tests, create a `testingConfig.js` file in `devConfig/` by copying `testingConfig.example.js` -* To run tests: - * To run all tests, including those that require LBC (like publishing), simply run `npm test` - * To run only tests that do not require LBC, run `npm run test:no-lbc` + +- This package uses `mocha` with `chai` for testing. +- Before running tests, create a `testingConfig.js` file in `devConfig/` by copying `testingConfig.example.js` +- To run tests: + - To run all tests, including those that require LBC (like publishing), simply run `npm test` + - To run only tests that do not require LBC, run `npm run test:no-lbc` ### URL formats -Spee.ch has a few types of URL formats that return different assets from the LBRY network. Below is a list of all possible URLs for the content on spee.ch. You can learn more about LBRY URLs [here](https://lbry.tech/resources/uri). -* retrieve the controlling `LBRY` claim: - * https://spee.ch/`claim` - * https://spee.ch/`claim`.`ext` (serve) -* retrieve a specific `LBRY` claim: - * https://spee.ch/`claim_id`/`claim` - * https://spee.ch/`claim_id`/`claim`.`ext` (serve) -* retrieve all contents for the controlling `LBRY` channel - * https://spee.ch/`@channel` -* a specific `LBRY` channel - * https://spee.ch/`@channel`:`channel_id` -* retrieve a specific claim within the controlling `LBRY` channel - * https://spee.ch/`@channel`/`claim` - * https://spee.ch/`@channel`/`claim`.`ext` (serve) -* retrieve a specific claim within a specific `LBRY` channel - * https://spee.ch/`@channel`:`channel_id`/`claim` - * https://spee.ch/`@channel`:`channel_id`/`claim`.`ext` (serve) +Spee.ch has a few types of URL formats that return different assets from the LBRY network. Below is a list of all possible URLs for the content on spee.ch. You can learn more about LBRY URLs [here](https://lbry.tech/resources/uri). + +- retrieve the controlling `LBRY` claim: + - https://spee.ch/`claim` + - https://spee.ch/`claim`.`ext` (serve) +- retrieve a specific `LBRY` claim: + - https://spee.ch/`claim_id`/`claim` + - https://spee.ch/`claim_id`/`claim`.`ext` (serve) +- retrieve all contents for the controlling `LBRY` channel + - https://spee.ch/`@channel` +- a specific `LBRY` channel + - https://spee.ch/`@channel`:`channel_id` +- retrieve a specific claim within the controlling `LBRY` channel + - https://spee.ch/`@channel`/`claim` + - https://spee.ch/`@channel`/`claim`.`ext` (serve) +- retrieve a specific claim within a specific `LBRY` channel + - https://spee.ch/`@channel`:`channel_id`/`claim` + - https://spee.ch/`@channel`:`channel_id`/`claim`.`ext` (serve) ### Dependencies Spee.ch depends on two other lbry technologies: - * [chainquery](https://github.com/lbryio/chainquery) - a normalized database of the blockchain data. We've provided credentials to use a public chainquery service. You can also install it on your own server to avoid being affected by the commons. - * [lbrynet](https://github.com/lbryio/lbry) - a daemon that handles your wallet and transactions. + +- [chainquery](https://github.com/lbryio/chainquery) - a normalized database of the blockchain data. We've provided credentials to use a public chainquery service. You can also install it on your own server to avoid being affected by the commons. +- [lbrynet](https://github.com/lbryio/lbry) - a daemon that handles your wallet and transactions. ### Bugs + If you find a bug or experience a problem, please report your issue here on GitHub and find us in the lbry discord! ## License diff --git a/cli/defaults/siteConfig.json b/cli/defaults/siteConfig.json index 67e4a79f..27275abc 100644 --- a/cli/defaults/siteConfig.json +++ b/cli/defaults/siteConfig.json @@ -53,11 +53,43 @@ }, "serving": { "markdownSettings": { - "skipHtml": true, - "privilegedDisallowedTypesDescriptions": ["Image"], - "privilegedDisallowedTypesMain": [], - "publicDisallowedTypesDescriptions": ["Image"], - "publicDisallowedTypesMain": [] + "skipHtmlMain": true, + "escapeHtmlMain": true, + "skipHtmlDescriptions": true, + "escapeHtmlDescriptions": true, + "allowedTypesMain": [], + "allowedTypesDescriptions": [], + "allowedTypesExample": [ + "see react-markdown docs", + "root", + "text", + "break", + "paragraph", + "emphasis", + "strong", + "thematicBreak", + "blockquote", + "delete", + "link", + "image", + "linkReference", + "imageReference", + "table", + "tableHead", + "tableBody", + "tableRow", + "tableCell", + "list", + "listItem", + "heading", + "inlineCode", + "code", + "html", + "parsedHtml" + ], + "disallowedTypesMain": [], + "disallowedTypesDescriptions": ["image", "html"], + "disallowedTypesExample": ["image", "html"] }, "customFileExtensions": { "application/x-troff-man": ".man", diff --git a/client/scss/_asset-display.scss b/client/scss/_asset-display.scss index b6d8dae0..7121f452 100644 --- a/client/scss/_asset-display.scss +++ b/client/scss/_asset-display.scss @@ -5,7 +5,7 @@ } .asset-document { - width: 100%; + max-width: 1000px; padding: $thin-padding; height: fit-content; box-sizing: border-box; @@ -16,15 +16,17 @@ } .asset-title { + max-width: 1000px; padding-bottom: $thin-padding; text-align: center; } .asset-image, .asset-video { - max-height: 95vh; - max-width: 95vw; + max-height: 75vh; + max-width: 85vw; object-fit: contain; object-position: center; + background: black; } /*below must die if this is intended to be shareable component! it also probably doesn't need to be*/ @@ -111,12 +113,15 @@ margin: $primary-padding; width: 100%; + @media (min-width: $break-point-tablet) { + padding: $primary-padding; + } @media (max-width: $break-point-tablet) { - margin: $primary-padding $secondary-padding; + padding: $tertiary-padding; } @media (max-width: $break-point-mobile) { - margin: $primary-padding 0; + margin: $tertiary-padding; } } @@ -125,4 +130,5 @@ padding-top: $primary-padding; margin-top: $primary-padding; color: $grey; + text-align: center; } diff --git a/client/scss/_markdown.scss b/client/scss/_markdown.scss index ed972f03..b835407f 100644 --- a/client/scss/_markdown.scss +++ b/client/scss/_markdown.scss @@ -1,22 +1,26 @@ .markdown-preview { - // Headers + + margin: $tertiary-padding 0px; + h1, h2, - h3, - h4, - h5, - h6 { + h3 { font-size: inherit; + font-weight: inherit; + margin: $tertiary-padding 0px; + } + + h4, h5, h6 { + font-size: $text-large; font-weight: 600; - margin-bottom: $tertiary-padding; - padding-top: $tertiary-padding; + margin: $tertiary-padding 0px; } // Paragraphs p { font-size: 1.15rem; - margin-bottom: $tertiary-padding; white-space: pre-line; + margin: $tertiary-padding 0px; svg { width: 1rem; @@ -29,10 +33,20 @@ } blockquote { - border-radius: 8px; background: $blockquote-background; padding: $tertiary-padding; min-width: 60%; + margin: $tertiary-padding; + p:first-child{ + margin-top: 0px; + } + p:last-child { + margin-bottom: 0px; + } + + div { + display: none; + } } // Strikethrough text @@ -42,10 +56,10 @@ // Tables table { width: 100%; - margin-bottom: 1.2rem; background-color: $base-color; border-spacing: 0; border: .5px solid $chrome-color; + margin: $tertiary-padding 0px; tr { td, @@ -77,9 +91,20 @@ margin-top: $tertiary-padding; padding: $secondary-padding; object-fit: scale-down; - max-width: 100%; - border: $subtle-border; box-sizing: border-box; + display: block; + margin-left: auto; + margin-right: auto; + max-width: 90vw; + } + + iframe { + display: block; + margin-left: auto; + margin-right: auto; + max-width: 90vw; + margin-top: $tertiary-padding 0px; + margin-bottom: $tertiary-padding 0px; } // Horizontal Rule @@ -114,7 +139,7 @@ a { color: $primary-color; - display: inline-block; + display: inline; } // Lists diff --git a/client/src/components/ErrorBoundary/index.jsx b/client/src/components/ErrorBoundary/index.jsx new file mode 100644 index 00000000..a52e38fc --- /dev/null +++ b/client/src/components/ErrorBoundary/index.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +class ErrorBoundary extends React.Component { + constructor(props) { + super(props); + this.state = { hasError: false }; + } + + componentDidCatch(error, info) { + // Display fallback UI + this.setState({ hasError: true }); + // You can also log the error to an error reporting service + console.log('Error occurred while rendering markdown') + } + + render() { + if (this.state.hasError) { + // You can render any custom fallback UI + return (

A component was prevented from crashing the App.

); + } + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/client/src/components/FileViewer/index.jsx b/client/src/components/FileViewer/index.jsx index 0d3d4866..84b75b5d 100644 --- a/client/src/components/FileViewer/index.jsx +++ b/client/src/components/FileViewer/index.jsx @@ -1,7 +1,8 @@ import React from 'react'; -import ReactMarkdown from 'react-markdown'; -// TODO: get markdown settings from siteConfig - +import ReactMarkdown from 'react-markdown/with-html'; +import { serving } from '@config/siteConfig.json'; +import ErrorBoundary from '@components/ErrorBoundary'; +const { markdownSettings: { escapeHtmlMain, skipHtmlMain, allowedTypesMain } } = serving; class FileViewer extends React.Component { constructor (props) { @@ -39,7 +40,9 @@ class FileViewer extends React.Component {
{ this.state.fileLoaded && - + + + } { !this.state.fileLoaded && diff --git a/client/src/containers/AssetInfo/view.jsx b/client/src/containers/AssetInfo/view.jsx index c1e6154d..ea095b0d 100644 --- a/client/src/containers/AssetInfo/view.jsx +++ b/client/src/containers/AssetInfo/view.jsx @@ -12,7 +12,8 @@ import { createPermanentURI } from '@clientutils/createPermanentURI'; import ReactMarkdown from 'react-markdown'; const { details: { host } } = siteConfig; - +const { serving } = siteConfig; +const { markdownSettings: { escapeHtmlDescriptions, skipHtmlDescriptions, allowedTypesDescriptions } } = serving; class AssetInfo extends React.Component { render () { const { editable, asset } = this.props; @@ -38,7 +39,17 @@ class AssetInfo extends React.Component { { description && ( } - content={
} + content={ +
+ +
+ } /> )} {editable && ( diff --git a/docs/settings.md b/docs/settings.md new file mode 100644 index 00000000..981132a3 --- /dev/null +++ b/docs/settings.md @@ -0,0 +1,96 @@ +Settings found in cli/defaults/siteConfig.json will be copied to /site/config/siteConfig.json by running npm run configure + +You are encouraged to dig into those settings to make your installation behave how you wish. Below is a description of settings available. + +ANALYTICS: + + "googleId": null + +ASSET DEFAULTS: _These are some default values for publishes_ + + "title": "Default Content Title", + "description": "Default Content Description", + "thumbnail": "https://spee.ch/0e5d4e8f4086e13f5b9ca3f9648f518e5f524402/speechflag.png" + +DETAILS: + + "port": 3000, - this is the internal server port for the application_ + "title": "My Site", + "ipAddress": "", + "host": "https://www.example.com", - must contain "http(s)://" and if localhost, "http://localhost:3000" + "description": "A decentralized hosting platform built on LBRY", + "twitter": false, + "blockListEndpoint": - the LBRY default endpoint is generally for the US. Empty string "" negates. + +PUBLISHING: + + "primaryClaimAddress": null, - generally supplied by your lbrynet sdk + "uploadDirectory": "/home/lbry/Uploads", - lbrynet sdk will know your uploads are here + "lbrynetHome": "/home/lbry", + "thumbnailChannel": null, - when publishing non-image content, thumbnails will go here. + "thumbnailChannelId": null, + "additionalClaimAddresses": [], + "disabled": false, + "disabledMessage": "Default publishing disabled message", + "closedRegistration": false, - true: prevent new channels from being registered + "serveOnlyApproved": false, - true: prevent your site from serving up unapproved channels + "publishOnlyApproved": false, - true: restrict + "approvedChannels": [], - If either of the above two are true, ['@MyKittens', '@BobsKittens'] + "publishingChannelWhitelist": [], + "channelClaimBidAmount": "0.1", - When creating a channel, how much you deposit to control the name + "fileClaimBidAmount": "0.01", - When publishing content, how much you deposit to control the name + "maxSizeImage": 10000000, - You may not want people uploading 50GB files. 1000000 = 1MB + "maxSizeGif": 50000000, + "maxSizeVideo": 50000000 + +SERVING: + + "markdownSettings": { + "skipHtmlMain": true, - false: render html, in a somewhat unpredictable way~ + "escapeHtmlMain": true, - true: rather than render html, escape it and print it visibly + "skipHtmlDescriptions": true, - as above, for descriptions + "escapeHtmlDescriptions": true, - as above, for descriptions + "allowedTypesMain": [], - markdown rendered as main content + "allowedTypesDescriptions": [], - markdown rendered in description in content details + "allowedTypesExample": [ - here are examples of allowed types + "see react-markdown docs", `https://github.com/rexxars/react-markdown` + "root", + "text", + "break", + "paragraph", + "emphasis", + "strong", + "thematicBreak", + "blockquote", + "delete", + "link", + "image", - you may not have a lot of control over how these are rendered + "linkReference", + "imageReference", + "table", + "tableHead", + "tableBody", + "tableRow", + "tableCell", + "list", + "listItem", + "heading", + "inlineCode", + "code", + "html", - potentially DANGEROUS, intended for `serveOnlyApproved = true` environments, includes iframes, divs. + "parsedHtml" + ], + "disallowedTypesMain": [], - not implemented + "disallowedTypesDescriptions": ["image", "html"], - not implemented + "disallowedTypesExample": ["image", "html"] - not implemented + }, + "customFileExtensions": { - suggest a file extension for experimental content types you may be publishing + "application/example-type": "example" + } + +STARTUP: + + "performChecks": true, + "performUpdates": true + +}