|
@ -17,7 +17,7 @@ updates:
|
|||
assignees:
|
||||
- kwypchlo
|
||||
- package-ecosystem: npm
|
||||
directory: "/packages/webapp"
|
||||
directory: "/packages/website"
|
||||
schedule:
|
||||
interval: weekly
|
||||
time: "10:00"
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
name: Deploy webapp to Skynet
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "packages/webapp/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: "Build webapp"
|
||||
run: yarn workspace webapp build
|
||||
env:
|
||||
GATSBY_API_URL: "https://siasky.net"
|
||||
|
||||
- name: "Deploy to Skynet"
|
||||
uses: kwypchlo/deploy-to-skynet-action@main
|
||||
with:
|
||||
upload-dir: packages/webapp/public
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@ -0,0 +1,46 @@
|
|||
name: Deploy website to Skynet
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "packages/website/**"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/website
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 15.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm i --force
|
||||
|
||||
- name: "Build website"
|
||||
run: npm run build
|
||||
|
||||
- name: "Integration tests"
|
||||
uses: cypress-io/github-action@v2
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
working-directory: packages/website
|
||||
install: false
|
||||
record: true
|
||||
start: npm run serve
|
||||
wait-on: "http://127.0.0.1:9000"
|
||||
|
||||
- name: "Deploy to Skynet"
|
||||
uses: kwypchlo/deploy-to-skynet-action@main
|
||||
with:
|
||||
upload-dir: packages/website/public
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
registry-seed: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && secrets.WEBSITE_REGISTRY_SEED || '' }}
|
|
@ -58,6 +58,9 @@ typings/
|
|||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
|
|
|
@ -32,11 +32,11 @@ Mongo needs a couple of extra steps in order to start a secure cluster.
|
|||
|
||||
- Open port 27017 on all nodes that will take part in the cluster. Ideally, you would only open the port for the other
|
||||
nodes in the cluster.
|
||||
- Manually run an initialisation `docker run` with extra environment variables that will initialise the admin user with
|
||||
a password (example below).
|
||||
- Manually add a `mgkey` file under `./docker/data/mongo` with the respective secret (
|
||||
see [Mongo's keyfile access control](https://docs.mongodb.com/manual/tutorial/enforce-keyfile-access-control-in-existing-replica-set/)
|
||||
for details).
|
||||
- Manually run an initialisation `docker run` with extra environment variables that will initialise the admin user with
|
||||
a password (example below).
|
||||
- During the initialisation run mentioned above, we need to make two extra steps within the container:
|
||||
- Change the ownership of `mgkey` to `mongodb:mongodb`
|
||||
- Change its permissions to 400
|
||||
|
|
|
@ -7,11 +7,6 @@ x-logging: &default-logging
|
|||
max-file: "3"
|
||||
|
||||
services:
|
||||
webapp:
|
||||
build:
|
||||
args:
|
||||
WITH_ACCOUNTS: 1 # enable accounts frontend
|
||||
|
||||
nginx:
|
||||
environment:
|
||||
- ACCOUNTS_ENABLED=1
|
||||
|
@ -124,7 +119,7 @@ services:
|
|||
- NEXT_PUBLIC_SKYNET_PORTAL_API=${SKYNET_PORTAL_API}
|
||||
- NEXT_PUBLIC_SKYNET_DASHBOARD_URL=${SKYNET_DASHBOARD_URL}
|
||||
- NEXT_PUBLIC_KRATOS_BROWSER_URL=${SKYNET_DASHBOARD_URL}/.ory/kratos/public
|
||||
- NEXT_PUBLIC_KRATOS_PUBLIC_URL=${SKYNET_DASHBOARD_URL}/.ory/kratos/public
|
||||
- NEXT_PUBLIC_KRATOS_PUBLIC_URL=http://oathkeeper:4455/.ory/kratos/public
|
||||
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${STRIPE_PUBLISHABLE_KEY}
|
||||
volumes:
|
||||
- ./docker/data/dashboard/.next:/usr/app/.next
|
||||
|
@ -133,6 +128,8 @@ services:
|
|||
ipv4_address: 10.10.10.85
|
||||
expose:
|
||||
- 3000
|
||||
depends_on:
|
||||
- oathkeeper
|
||||
|
||||
oathkeeper:
|
||||
image: oryd/oathkeeper:v0.38
|
||||
|
|
|
@ -82,16 +82,17 @@ services:
|
|||
- sia
|
||||
- health-check
|
||||
- handshake-api
|
||||
- website
|
||||
|
||||
webapp:
|
||||
website:
|
||||
build:
|
||||
context: ./packages/webapp
|
||||
context: ./packages/website
|
||||
dockerfile: Dockerfile
|
||||
container_name: webapp
|
||||
container_name: website
|
||||
restart: unless-stopped
|
||||
logging: *default-logging
|
||||
volumes:
|
||||
- ./docker/data/webapp/.cache:/usr/app/.cache
|
||||
env_file:
|
||||
- .env
|
||||
networks:
|
||||
shared:
|
||||
ipv4_address: 10.10.10.35
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:15.12.0-alpine
|
||||
FROM node:15.14.0-alpine
|
||||
|
||||
WORKDIR /opt/hsd
|
||||
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=skynet:10m max_size=10g inactive=24h use_temp_path=off;
|
||||
|
||||
# this runs before forking out nginx worker processes
|
||||
init_by_lua_block {
|
||||
require "cjson"
|
||||
require "socket.http"
|
||||
}
|
||||
|
||||
# ratelimit specified IPs
|
||||
geo $limit {
|
||||
default 0;
|
||||
|
@ -78,11 +84,11 @@ server {
|
|||
|
||||
include /etc/nginx/conf.d/include/cors;
|
||||
|
||||
proxy_pass http://webapp:9000;
|
||||
proxy_pass http://website:9000;
|
||||
}
|
||||
|
||||
location /docs {
|
||||
proxy_pass https://skynethq.github.io/skynet-docs;
|
||||
proxy_pass https://skynetlabs.github.io/skynet-docs;
|
||||
}
|
||||
|
||||
location /skynet/blocklist {
|
||||
|
@ -296,12 +302,11 @@ server {
|
|||
|
||||
if ngx.status == ngx.HTTP_OK or ngx.status == ngx.HTTP_NOT_FOUND then
|
||||
local http = require("socket.http")
|
||||
local headers = { Cookie = ngx.req.get_headers()["Cookie"] }
|
||||
local method = ngx.req.get_method() == ngx.HTTP_GET and "read" or "write"
|
||||
local ok, statusCode, headers, statusText = http.request {
|
||||
url = "http://accounts:3000/track/registry/" .. method,
|
||||
method = "POST",
|
||||
headers = headers
|
||||
headers = ngx.req.get_headers()
|
||||
}
|
||||
if statusCode ~= ngx.HTTP_NO_CONTENT and statusCode ~= ngx.HTTP_UNAUTHORIZED then
|
||||
ngx.log(ngx.ERR, "accounts endpoint /track/registry/" .. method .. " failed with error " .. statusCode)
|
||||
|
@ -362,8 +367,11 @@ server {
|
|||
local skylink = ngx.header["Skynet-Skylink"]
|
||||
if skylink and ngx.status >= ngx.HTTP_OK and ngx.status < ngx.HTTP_SPECIAL_RESPONSE then
|
||||
local http = require("socket.http")
|
||||
local headers = { Cookie = ngx.req.get_headers()["Cookie"] }
|
||||
local ok, statusCode, headers, statusText = http.request { url = "http://accounts:3000/track/upload/" .. skylink, method = "POST", headers = headers }
|
||||
local ok, statusCode, headers, statusText = http.request {
|
||||
url = "http://accounts:3000/track/upload/" .. skylink,
|
||||
method = "POST",
|
||||
headers = ngx.req.get_headers()
|
||||
}
|
||||
if statusCode ~= ngx.HTTP_NO_CONTENT and statusCode ~= ngx.HTTP_UNAUTHORIZED then
|
||||
ngx.log(ngx.ERR, "accounts endpoint /track/upload/" .. skylink .. " failed with error " .. statusCode)
|
||||
end
|
||||
|
@ -408,12 +416,11 @@ server {
|
|||
local skylink = ngx.header["Skynet-Skylink"]
|
||||
if skylink and ngx.status >= ngx.HTTP_OK and ngx.status < ngx.HTTP_SPECIAL_RESPONSE then
|
||||
local http = require("socket.http")
|
||||
local headers = { Cookie = ngx.req.get_headers()["Cookie"] }
|
||||
local query = table.concat({ "status=" .. ngx.status, "bytes=" .. ngx.var.body_bytes_sent }, "&")
|
||||
local ok, statusCode, headers, statusText = http.request {
|
||||
url = "http://accounts:3000/track/download/" .. skylink .. "?" .. query,
|
||||
method = "POST",
|
||||
headers = headers
|
||||
headers = ngx.req.get_headers()
|
||||
}
|
||||
if statusCode ~= ngx.HTTP_NO_CONTENT and statusCode ~= ngx.HTTP_UNAUTHORIZED then
|
||||
ngx.log(ngx.ERR, "accounts endpoint /track/download/" .. skylink .. " failed with error " .. statusCode)
|
||||
|
@ -458,6 +465,33 @@ server {
|
|||
proxy_pass http://127.0.0.1/$uri?attachment=true&$args;
|
||||
}
|
||||
|
||||
location /__internal/do/not/use/authenticated {
|
||||
include /etc/nginx/conf.d/include/cors;
|
||||
|
||||
charset utf-8;
|
||||
charset_types application/json;
|
||||
default_type application/json;
|
||||
|
||||
content_by_lua_block {
|
||||
local json = require('cjson')
|
||||
-- this block runs only when accounts are enabled
|
||||
if os.getenv("ACCOUNTS_ENABLED", "0") == "0" then
|
||||
ngx.say(json.encode{authenticated = false})
|
||||
return ngx.exit(ngx.HTTP_OK)
|
||||
end
|
||||
|
||||
local res = ngx.location.capture("/accounts/user", { copy_all_vars = true })
|
||||
if res.status == ngx.HTTP_OK then
|
||||
local limits = json.decode(res.body)
|
||||
ngx.say(json.encode{authenticated = limits.tier > 0})
|
||||
return ngx.exit(ngx.HTTP_OK)
|
||||
end
|
||||
|
||||
ngx.say(json.encode{authenticated = false})
|
||||
return ngx.exit(ngx.HTTP_OK)
|
||||
}
|
||||
}
|
||||
|
||||
location /accounts {
|
||||
internal; # internal endpoint only
|
||||
access_log off; # do not log traffic
|
||||
|
|
|
@ -3,12 +3,12 @@ FROM golang AS sia-builder
|
|||
ENV GOOS linux
|
||||
ENV GOARCH amd64
|
||||
|
||||
ARG branch=master
|
||||
ARG branch=portal-latest
|
||||
|
||||
RUN git clone https://gitlab.com/SkynetLabs/skyd.git Sia --single-branch --branch ${branch}
|
||||
RUN make release --directory Sia
|
||||
|
||||
FROM nebulouslabs/sia:1.5.5
|
||||
FROM nebulouslabs/sia:latest
|
||||
|
||||
COPY --from=sia-builder /go/bin/skyd /usr/bin/siad
|
||||
COPY --from=sia-builder /go/bin/skyc /usr/bin/siac
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:15.12.0-alpine
|
||||
FROM node:15.14.0-alpine
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
|
@ -10,6 +10,7 @@ RUN yarn --no-lockfile
|
|||
COPY public ./public
|
||||
COPY src ./src
|
||||
COPY styles ./styles
|
||||
COPY next.config.js .
|
||||
COPY postcss.config.js .
|
||||
COPY tailwind.config.js .
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
future: {
|
||||
webpack5: true,
|
||||
},
|
||||
};
|
|
@ -4,6 +4,7 @@ import SelfServiceMessages from "./SelfServiceMessages";
|
|||
|
||||
export default function SelfServiceForm({ flow, config, fieldsConfig, title, button = "Submit" }) {
|
||||
const fields = config.fields
|
||||
.filter((field) => !field.name.startsWith("traits.name")) // drop name fields
|
||||
.map((field) => ({ ...field, ...fieldsConfig[field.name] }))
|
||||
.sort((a, b) => (a.position < b.position ? -1 : 1));
|
||||
const formik = useFormik({
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
import { Client, Environment } from "square";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
|
||||
const client = new Client({
|
||||
environment: Environment.Sandbox,
|
||||
accessToken: process.env.SQUARE_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
const api = {
|
||||
GET: async (req, res) => {
|
||||
const user = "R7R0NY1Z8WT11D43564EEFKTYR"; // req.headers["x-user"];
|
||||
|
||||
try {
|
||||
const { result: customerResult } = await client.customersApi.retrieveCustomer(user);
|
||||
const { customer } = customerResult;
|
||||
|
||||
res.json(customer.cards);
|
||||
} catch (error) {
|
||||
res.json([]);
|
||||
}
|
||||
},
|
||||
// POST: async (req, res) => {
|
||||
// const user = req.headers["x-user"];
|
||||
// const card = {
|
||||
// cardNonce: "YOUR_CARD_NONCE",
|
||||
// cardholderName: "Amelia Earhart",
|
||||
// billingAddress: {},
|
||||
// verificationToken: "verification_token0",
|
||||
// };
|
||||
|
||||
// card.bodyBillingAddress.addressLine1 = "500 Electric Ave";
|
||||
// card.bodyBillingAddress.addressLine2 = "Suite 600";
|
||||
// card.bodyBillingAddress.addressLine3 = "address_line_38";
|
||||
// card.bodyBillingAddress.locality = "New York";
|
||||
// card.bodyBillingAddress.sublocality = "sublocality2";
|
||||
// card.bodyBillingAddress.administrativeDistrictLevel1 = "NY";
|
||||
// card.bodyBillingAddress.postalCode = "10003";
|
||||
// card.bodyBillingAddress.country = "US";
|
||||
|
||||
// try {
|
||||
// const { result } = await client.customersApi.createCustomerCard(user, card);
|
||||
|
||||
// res.status(StatusCodes.NO_CONTENT);
|
||||
// } catch (error) {
|
||||
// console.log(Object.keys(error));
|
||||
|
||||
// res.status(StatusCodes.BAD_REQUEST);
|
||||
// }
|
||||
// },
|
||||
};
|
||||
|
||||
export default (req, res) => {
|
||||
if (req.method in api) {
|
||||
api[req.method](req, res);
|
||||
} else {
|
||||
res.status(StatusCodes.NOT_FOUND);
|
||||
}
|
||||
};
|
|
@ -1,45 +0,0 @@
|
|||
import { Client, Environment } from "square";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
|
||||
const client = new Client({
|
||||
environment: Environment.Sandbox,
|
||||
accessToken: process.env.SQUARE_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
const api = {
|
||||
GET: async (req, res) => {
|
||||
const user = "NBE7TRXZPGZXNBD64JB6DR5AGR"; // req.headers["x-user"];
|
||||
|
||||
try {
|
||||
// get locations for invoices search query
|
||||
const { result: locationsResponse } = await client.locationsApi.listLocations();
|
||||
const { locations } = locationsResponse;
|
||||
|
||||
// create invoices serach query
|
||||
const locationIds = locations.map(({ id }) => id);
|
||||
const customerIds = [user];
|
||||
const filter = { locationIds, customerIds };
|
||||
const sort = { field: "INVOICE_SORT_DATE", order: "DESC" };
|
||||
const query = { filter, sort };
|
||||
|
||||
// query invoices with given search criteria
|
||||
const { result: invoicesResponse } = await client.invoicesApi.searchInvoices({ query, limit: 10 });
|
||||
const { invoices } = invoicesResponse;
|
||||
|
||||
res.json(invoices);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log(error?.errors);
|
||||
|
||||
res.json([]); // todo: error handling
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default (req, res) => {
|
||||
if (req.method in api) {
|
||||
return api[req.method](req, res);
|
||||
}
|
||||
|
||||
return res.status(StatusCodes.NOT_FOUND);
|
||||
};
|
|
@ -1,46 +0,0 @@
|
|||
import { Client, Environment } from "square";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
|
||||
const client = new Client({
|
||||
environment: Environment.Sandbox,
|
||||
accessToken: process.env.SQUARE_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
const api = {
|
||||
GET: async (req, res) => {
|
||||
try {
|
||||
const user = "NBE7TRXZPGZXNBD64JB6DR5AGR"; // req.headers["x-user"];
|
||||
|
||||
// create subscriptions search query
|
||||
const query = { filter: { customerIds: [user] } };
|
||||
|
||||
// query subscriptions with given search criteria
|
||||
const { result: subscriptionsResponse } = await client.subscriptionsApi.searchSubscriptions({ query });
|
||||
const { subscriptions } = subscriptionsResponse;
|
||||
|
||||
// get active subscription
|
||||
const subscription = subscriptions.find(({ status }) => status === "ACTIVE");
|
||||
|
||||
if (!subscription) {
|
||||
return res.status(StatusCodes.NO_CONTENT).end(); // no active subscription found
|
||||
}
|
||||
|
||||
console.log("....", subscription);
|
||||
|
||||
return res.json(subscription);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log(error?.errors);
|
||||
|
||||
return res.status(StatusCodes.BAD_REQUEST).end(); // todo: error handling
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default (req, res) => {
|
||||
if (req.method in api) {
|
||||
return api[req.method](req, res);
|
||||
}
|
||||
|
||||
return res.status(StatusCodes.NOT_FOUND).end();
|
||||
};
|
|
@ -1,55 +0,0 @@
|
|||
import { Client, Environment } from "square";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
|
||||
const client = new Client({
|
||||
environment: Environment.Sandbox,
|
||||
accessToken: process.env.SQUARE_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
const cancelSubscription = async (id) => {
|
||||
const { result: subscriptionsResponse } = await client.subscriptionsApi.cancelSubscription(id);
|
||||
const { subscription } = subscriptionsResponse;
|
||||
|
||||
return subscription;
|
||||
};
|
||||
|
||||
const getActiveSubscription = async (customerId) => {
|
||||
// create subscriptions search query
|
||||
const query = { filter: { customerIds: [customerId] } };
|
||||
|
||||
// query subscriptions with given search criteria
|
||||
const { result: subscriptionsResponse } = await client.subscriptionsApi.searchSubscriptions({ query });
|
||||
const { subscriptions } = subscriptionsResponse;
|
||||
|
||||
// get active subscription with a set cancellation date
|
||||
return subscriptions.find(({ status, canceledDate }) => status === "ACTIVE" && !canceledDate);
|
||||
};
|
||||
|
||||
const api = {
|
||||
POST: async (req, res) => {
|
||||
try {
|
||||
const user = "NBE7TRXZPGZXNBD64JB6DR5AGR"; // req.headers["x-user"];
|
||||
const subscription = await getActiveSubscription(user);
|
||||
|
||||
if (!subscription) {
|
||||
return res.status(StatusCodes.BAD_REQUEST).end(); // no active subscription found
|
||||
}
|
||||
|
||||
const canceledSubscription = await cancelSubscription(subscription.id);
|
||||
|
||||
return res.json(canceledSubscription);
|
||||
} catch (error) {
|
||||
console.log(error.errors);
|
||||
|
||||
return res.status(StatusCodes.BAD_REQUEST).end(); // todo: error handling
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default (req, res) => {
|
||||
if (req.method in api) {
|
||||
return api[req.method](req, res);
|
||||
}
|
||||
|
||||
return res.status(StatusCodes.NOT_FOUND).end();
|
||||
};
|
|
@ -1,58 +0,0 @@
|
|||
import { Client, Environment } from "square";
|
||||
import { StatusCodes } from "http-status-codes";
|
||||
|
||||
const client = new Client({
|
||||
environment: Environment.Sandbox,
|
||||
accessToken: process.env.SQUARE_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
const updateSubscription = async (id, body) => {
|
||||
const { result: subscriptionsResponse } = await client.subscriptionsApi.updateSubscription(id, body);
|
||||
const { subscription } = subscriptionsResponse;
|
||||
|
||||
return subscription;
|
||||
};
|
||||
|
||||
const getActiveCanceledSubscription = async (customerId) => {
|
||||
// create subscriptions search query
|
||||
const query = { filter: { customerIds: [customerId] } };
|
||||
|
||||
// query subscriptions with given search criteria
|
||||
const { result: subscriptionsResponse } = await client.subscriptionsApi.searchSubscriptions({ query });
|
||||
const { subscriptions } = subscriptionsResponse;
|
||||
|
||||
// get active subscription with a set cancellation date
|
||||
return subscriptions.find(({ status, canceledDate }) => status === "ACTIVE" && canceledDate);
|
||||
};
|
||||
|
||||
const api = {
|
||||
POST: async (req, res) => {
|
||||
try {
|
||||
const user = "NBE7TRXZPGZXNBD64JB6DR5AGR"; // req.headers["x-user"];
|
||||
const subscription = await getActiveCanceledSubscription(user);
|
||||
|
||||
if (!subscription) {
|
||||
return res.status(StatusCodes.BAD_REQUEST).end(); // no active subscription with cancel date found
|
||||
}
|
||||
|
||||
// update the subscription setting empty canceledDate
|
||||
const updatedSubscription = await updateSubscription(subscription.id, {
|
||||
subscription: { ...subscription, canceledDate: "" },
|
||||
});
|
||||
|
||||
return res.json(updatedSubscription);
|
||||
} catch (error) {
|
||||
console.log(error.errors);
|
||||
|
||||
return res.status(StatusCodes.BAD_REQUEST).end(); // todo: error handling
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default (req, res) => {
|
||||
if (req.method in api) {
|
||||
return api[req.method](req, res);
|
||||
}
|
||||
|
||||
return res.status(StatusCodes.NOT_FOUND).end();
|
||||
};
|
|
@ -53,7 +53,6 @@ export default async (req, res) => {
|
|||
|
||||
res.json({ sessionId: session.id });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
res.status(StatusCodes.BAD_REQUEST).json({ error: { message: error.message } });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -200,7 +200,7 @@ export default function Home({ plans }) {
|
|||
<div className="ml-5 w-0 flex-1">
|
||||
<dt className="text-sm font-medium text-gray-500 truncate">Storage used</dt>
|
||||
<dd className="flex items-baseline">
|
||||
<div className="text-2xl font-semibold text-grey-900">{prettyBytes(stats?.storageUsed ?? 0)}</div>
|
||||
<div className="text-2xl font-semibold text-grey-900">{prettyBytes(stats?.totalUploadsSize ?? 0)}</div>
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -83,7 +83,9 @@ export default function Payments({ plans, user: initialUserData, stats: initialS
|
|||
<div className="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<dt className="text-sm font-medium text-gray-500 truncate">Storage used</dt>
|
||||
<dd className="mt-1 text-3xl font-semibold text-gray-900">{prettyBytes(stats.storageUsed)}</dd>
|
||||
<dd className="mt-1 text-3xl font-semibold text-gray-900">
|
||||
{prettyBytes(stats?.totalUploadsSize ?? 0)}
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
</dl>
|
||||
|
|
|
@ -30,14 +30,10 @@ export const getServerSideProps = authServerSideProps(async (context) => {
|
|||
headers: { cookie: context.req.headers.cookie },
|
||||
});
|
||||
|
||||
console.log(flow, status, data);
|
||||
|
||||
if (status === 200) return { props: { flow: data } };
|
||||
|
||||
throw new Error(`Failed to retrieve flow ${flow} with code ${status}`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
return {
|
||||
redirect: {
|
||||
permanent: false,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:15.12.0-alpine
|
||||
FROM node:15.14.0-alpine
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:15.12.0-alpine
|
||||
FROM node:15.14.0-alpine
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"deep-object-diff": "^1.1.0",
|
||||
"express": "^4.17.1",
|
||||
"http-status-codes": "^2.1.2",
|
||||
|
|
|
@ -5,7 +5,6 @@ if (!process.env.PORTAL_URL) {
|
|||
}
|
||||
|
||||
const express = require("express");
|
||||
const bodyparser = require("body-parser");
|
||||
const db = require("./db");
|
||||
|
||||
const host = process.env.HOSTNAME || "0.0.0.0";
|
||||
|
@ -13,8 +12,8 @@ const port = Number(process.env.PORT) || 3100;
|
|||
|
||||
const server = express();
|
||||
|
||||
server.use(bodyparser.urlencoded({ extended: false }));
|
||||
server.use(bodyparser.json());
|
||||
server.use(express.urlencoded({ extended: false }));
|
||||
server.use(express.json());
|
||||
server.use((req, res, next) => {
|
||||
db.read();
|
||||
next();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
package-lock.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:15.12.0-alpine
|
||||
FROM node:15.14.0-alpine
|
||||
|
||||
RUN apk update && apk add autoconf automake libtool gcc make g++ zlib-dev file nasm util-linux
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variable files
|
||||
.env*
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# Npm
|
||||
# package-lock.json
|
||||
|
||||
# Cypress
|
||||
cypress/screenshots
|
||||
cypress/videos
|
|
@ -0,0 +1,4 @@
|
|||
.cache
|
||||
package.json
|
||||
package-lock.json
|
||||
public
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"printWidth": 120
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
module.exports = {
|
||||
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||
addons: [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
{
|
||||
name: "@storybook/addon-postcss",
|
||||
options: {
|
||||
postcssLoaderOptions: {
|
||||
implementation: require("postcss"),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
webpackFinal: async (config) => {
|
||||
// Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
|
||||
config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/];
|
||||
// use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
|
||||
config.module.rules[0].use[0].loader = require.resolve("babel-loader");
|
||||
// use @babel/preset-react for JSX and env (instead of staged presets)
|
||||
config.module.rules[0].use[0].options.presets = [
|
||||
require.resolve("@babel/preset-react"),
|
||||
require.resolve("@babel/preset-env"),
|
||||
];
|
||||
config.module.rules[0].use[0].options.plugins = [
|
||||
// use @babel/plugin-proposal-class-properties for class arrow functions
|
||||
require.resolve("@babel/plugin-proposal-class-properties"),
|
||||
// use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
|
||||
require.resolve("babel-plugin-remove-graphql-queries"),
|
||||
];
|
||||
|
||||
// implement svg import support
|
||||
config.module.rules.find((rule) => rule.test && rule.test.test(".svg")).exclude = /\.svg$/;
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/,
|
||||
enforce: "pre",
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve("react-svg-loader"),
|
||||
options: { svgo: { plugins: [{ removeViewBox: false }] } },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
|
||||
config.resolve.mainFields = ["browser", "module", "main"];
|
||||
return config;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
import { action } from "@storybook/addon-actions";
|
||||
import "normalize.css";
|
||||
import "@fontsource/sora";
|
||||
import "@fontsource/source-sans-pro";
|
||||
import "./tailwind.css";
|
||||
|
||||
// Gatsby's Link overrides:
|
||||
// Gatsby Link calls the `enqueue` & `hovering` methods on the global variable ___loader.
|
||||
// This global object isn't set in storybook context, requiring you to override it to empty functions (no-op),
|
||||
// so Gatsby Link doesn't throw any errors.
|
||||
global.___loader = {
|
||||
enqueue: () => {},
|
||||
hovering: () => {},
|
||||
};
|
||||
// This global variable is prevents the "__BASE_PATH__ is not defined" error inside Storybook.
|
||||
global.__BASE_PATH__ = "/";
|
||||
|
||||
// Navigating through a gatsby app using gatsby-link or any other gatsby component will use the `___navigate` method.
|
||||
// In Storybook it makes more sense to log an action than doing an actual navigate. Checkout the actions addon docs for more info: https://github.com/storybookjs/storybook/tree/master/addons/actions.
|
||||
|
||||
window.___navigate = (pathname) => {
|
||||
action("NavigateTo:")(pathname);
|
||||
};
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
layout: "fullscreen",
|
||||
viewport: {
|
||||
viewports: {
|
||||
mobile: {
|
||||
name: "Mobile",
|
||||
styles: {
|
||||
height: "667px",
|
||||
width: "375px",
|
||||
},
|
||||
type: "mobile",
|
||||
},
|
||||
tablet: {
|
||||
name: "Tablet",
|
||||
styles: {
|
||||
height: "1366px",
|
||||
width: "1024px",
|
||||
},
|
||||
type: "tablet",
|
||||
},
|
||||
},
|
||||
},
|
||||
backgrounds: {
|
||||
default: "light",
|
||||
values: [
|
||||
{ name: "dark", value: "#0d0d0d" },
|
||||
{ name: "light", value: "#ffffff" },
|
||||
],
|
||||
},
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
@import "tailwindcss/base";
|
||||
@import "tailwindcss/components";
|
||||
@import "tailwindcss/utilities";
|
|
@ -0,0 +1,27 @@
|
|||
FROM node:15.14.0-alpine
|
||||
|
||||
RUN apk update && apk add autoconf automake build-base libtool nasm pkgconfig
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
COPY package.json .
|
||||
COPY package-lock.json .
|
||||
|
||||
ENV GATSBY_TELEMETRY_DISABLED 1
|
||||
RUN npm i
|
||||
|
||||
COPY data ./data
|
||||
COPY src ./src
|
||||
COPY static ./static
|
||||
COPY gatsby-browser.js .
|
||||
COPY gatsby-config.js .
|
||||
COPY gatsby-node.js .
|
||||
COPY gatsby-ssr.js .
|
||||
COPY postcss.config.js .
|
||||
COPY tailwind.config.js .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
CMD ["sh", "-c", "npm run serve -- --host 0.0.0.0"]
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"baseUrl": "http://127.0.0.1:9000",
|
||||
"projectId": "gey76p",
|
||||
"videoUploadOnPasses": false
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context("Skynet website", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit("");
|
||||
});
|
||||
|
||||
it("should render page title", () => {
|
||||
cy.contains("Decentralized Internet");
|
||||
});
|
||||
|
||||
// it("should be able to upload a file", () => {
|
||||
// cy.intercept("POST", "/skynet/skyfile").as("upload");
|
||||
|
||||
// const fileName = "check.json";
|
||||
|
||||
// cy.wait(1000); // delay for drag-and-drop to work properly every time
|
||||
// cy.get('.home-upload input[type="file"]').attachFile(fileName, { subjectType: "drag-n-drop" });
|
||||
|
||||
// cy.get(".home-upload").scrollIntoView();
|
||||
// cy.get(".home-uploaded-files").children().should("have.length", 1);
|
||||
|
||||
// // wait max 2 minutes, the portal might be slow at times
|
||||
// cy.wait("@upload", { responseTimeout: 2 * 60 * 1000 });
|
||||
|
||||
// cy.contains(".upload-file", fileName).within(() => {
|
||||
// cy.get(".url")
|
||||
// .invoke("text")
|
||||
// .should("match", /\/[a-zA-Z0-9-_]{46}/);
|
||||
|
||||
// cy.contains("Copy Link").click();
|
||||
// cy.contains("Copied!").should("be.visible");
|
||||
// });
|
||||
// });
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
/// <reference types="cypress" />
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
|
||||
import "cypress-file-upload";
|
|
@ -0,0 +1,20 @@
|
|||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
|
@ -0,0 +1,52 @@
|
|||
- header: Skynet Labs
|
||||
links:
|
||||
- title: About us
|
||||
to: /about
|
||||
- title: Brand Guidelines
|
||||
href: https://support.siasky.net/key-concepts/skynet-brand-guidelines
|
||||
- title: Careers
|
||||
href: https://jobs.lever.co/nebulous
|
||||
- title: Terms of Use
|
||||
href: /terms.pdf
|
||||
- title: Privacy Policy
|
||||
href: /privacy.pdf
|
||||
- header: Developers
|
||||
links:
|
||||
- title: Developer Guide
|
||||
href: https://support.siasky.net/the-technology/developing-on-skynet
|
||||
- title: API & SDK Documentation
|
||||
href: https://siasky.net/docs/
|
||||
- title: Portal Setup
|
||||
href: https://support.siasky.net/the-technology/running-a-web-portal
|
||||
- title: Github
|
||||
href: https://github.com/SkynetLabs
|
||||
- title: Gitlab
|
||||
href: https://gitlab.com/SkynetLabs
|
||||
- header: Technology
|
||||
links:
|
||||
- title: What is Skynet?
|
||||
href: https://support.siasky.net
|
||||
- title: Frequent Questions
|
||||
href: https://support.siasky.net/key-concepts/faqs
|
||||
- title: Skynet Wiki
|
||||
href: https://skynetwiki.tech
|
||||
- title: Support
|
||||
href: https://support.siasky.net
|
||||
- header: Ecosystem
|
||||
links:
|
||||
- title: Sia Foundation
|
||||
href: https://sia.tech
|
||||
- title: Sia Foundation Forum
|
||||
href: https://forum.sia.tech
|
||||
- title: SiaStats
|
||||
href: https://siastats.info
|
||||
- title: Skynet AppStore
|
||||
href: https://skapp.hns.siasky.net/
|
||||
- header: Skynet Webportals
|
||||
links:
|
||||
- title: Siasky.net
|
||||
href: https://siasky.net
|
||||
- title: SkyPortal.xyz
|
||||
href: https://skyportal.xyz
|
||||
- title: Skydrain.net
|
||||
href: https://skydrain.net
|
|
@ -0,0 +1,22 @@
|
|||
- name: A.Capital Ventures
|
||||
image: ./investors/investors-logo-1.png
|
||||
- name: Bain Capital
|
||||
image: ./investors/investors-logo-2.png
|
||||
- name: Bessemer Venture Partners
|
||||
image: ./investors/investors-logo-3.png
|
||||
- name: Collab
|
||||
image: ./investors/investors-logo-4.png
|
||||
- name: Dragonfly Capital
|
||||
image: ./investors/investors-logo-5.png
|
||||
- name: Fenbushi Capital
|
||||
image: ./investors/investors-logo-6.png
|
||||
- name: First Star Ventures
|
||||
image: ./investors/investors-logo-7.png
|
||||
- name: Hack VC
|
||||
image: ./investors/investors-logo-8.png
|
||||
- name: INBlockchain
|
||||
image: ./investors/investors-logo-9.png
|
||||
- name: Paradigm
|
||||
image: ./investors/investors-logo-10.png
|
||||
- name: SV Angel
|
||||
image: ./investors/investors-logo-11.png
|
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,22 @@
|
|||
navigation:
|
||||
- title: Home
|
||||
to: /
|
||||
- title: About
|
||||
to: /about
|
||||
- title: Developers
|
||||
to: /developers
|
||||
- title: News
|
||||
to: /news
|
||||
team:
|
||||
- name: "Chris Schinnerl"
|
||||
position: "VP of Technology"
|
||||
image: images/team/chris-schinnerl.png
|
||||
social:
|
||||
- github: https://github.com/ChrisSchinnerl
|
||||
- gitlab: https://gitlab.com/ChrisSchinnerl
|
||||
- twitter: https://twitter.com/ChrisSchinnerl
|
||||
- name: Steve Funk
|
||||
position: Head of Support
|
||||
image: images/team/steve-funk.png
|
||||
social:
|
||||
- linkedin: https://www.linkedin.com/in/stevengfunk
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "A Deep Dive into Skynet"
|
||||
date: "2021-02-09"
|
||||
description: An introduction and a point of reference on all things Skynet. Intended for all audiences & each section has been written to be…
|
||||
thumbnail: ./thumbnail.png
|
||||
categories: ["blog"]
|
||||
author: David Vorick
|
||||
avatar: ../../team/david-vorick.png
|
||||
external: https://blog.sia.tech/a-deep-dive-into-skynet-a0fa037feea
|
||||
---
|
After Width: | Height: | Size: 525 KiB |
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "Announcing Skynet Premium Plans: Faster Speeds and Longer Pinning"
|
||||
date: "2021-03-24"
|
||||
description: Skynet Labs announces accounts with faster speeds and greater amounts of stored data, laying the foundation for future content…
|
||||
thumbnail: ./thumbnail.png
|
||||
categories: ["blog"]
|
||||
author: David Vorick
|
||||
avatar: ../../team/david-vorick.png
|
||||
external: https://blog.sia.tech/announcing-skynet-premium-plans-faster-speeds-and-longer-pinning-b5469814d2c3
|
||||
---
|
After Width: | Height: | Size: 397 KiB |
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "Built to Explore: The Skynet Spring 2021 Hackathon!"
|
||||
date: "2021-04-01"
|
||||
description: Put your DApp to the test with real end-users in this exciting 3 phase hackathon. $25,000+ in prizes and open to devs and nondevs alike!
|
||||
thumbnail: ./thumbnail.png
|
||||
categories: ["blog"]
|
||||
author: David Vorick
|
||||
avatar: ../../team/david-vorick.png
|
||||
external: https://blog.sia.tech/built-to-explore-the-skynet-spring-2021-hackathon-a0cff382bb0c
|
||||
---
|
After Width: | Height: | Size: 2.3 MiB |
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title: "Sia Announces $3M Seed Round to Accelerate Development and Adoption of the Web3 platform Skynet"
|
||||
date: "2020-09-22"
|
||||
description: "Paradigm leads the round of financing; Nebulous to solely focus on Skynet"
|
||||
author: "Skynet Labs"
|
||||
categories: ["press release"]
|
||||
avatar: "../images/skynet-avatar.png"
|
||||
thumbnail: "../images/press-release.png"
|
||||
---
|
||||
|
||||
**Boston, MA – September 22nd, 2020** — Nebulous, the company building the Sia decentralized cloud storage platform and the Skynet application hosting platform, today announced it has closed a \$3M funding round led by Paradigm with participation from Bain Capital Ventures, Bessemer Venture Partners, A.Capital, Collaborative Fund, Dragonfly Capital Partners, Hack VC, INBlockchain, First Star Ventures, and other notable investors. The round will help the company scale and accelerate the development and adoption of Skynet.
|
||||
|
||||
Today’s internet monopolized by tech giants struggles with fundamental challenges in privacy, reliability, and has excessive control over our data and the way we interact with the world. Skynet enables high speed, low cost, and superior infrastructure to serve as the storage foundation for a free Internet. Where data is globally accessible, user-controlled, censorship-resistant, and not fragmented in walled gardens.
|
||||
|
||||
Skynet empowers developers to deploy applications to a decentralized network in just minutes and be immediately available to everyone across the world. Importantly, end-users can directly access content on Skynet without needing to run full nodes or deal with cryptocurrencies. It paves the path for more powerful applications, more dynamic user experiences, and disintermediates the web to ensure that publishers and creators are paid the full amount that they deserve. Skynet enables the decentralized web ecosystem to realize the full potential of a free internet.
|
||||
|
||||
“The possibilities created by Skynet blow our minds. The project has enabled a growing ecosystem of builders to quickly prototype censorship-resistant applications and interactive websites including interfaces to Ethereum smart contracts like Uniswap,” said Dan Robinson, Research Partner at Paradigm. “We’re investing in the Skynet team because we believe they have the right combination of talent, experience, and community to shepherd us into the era of the Decentralized Web.”
|
||||
|
||||
Nebulous launched the Skynet platform back in February 2020 and since then has seen accelerated growth in developer interest and usage. More than 1.6 million files have been uploaded and shared amounting to 10+ TB of data using Skynet. A thriving community of developers has built over 100 applications in the span of a few months including a Video Streaming app SkyLive, Blogging apps like Wakio and Skyblog Builder, Video & Image gallery app SkyGallery, and a Decentralized AppStore Skydroid. The full list of Skynet Apps can be explored at the Skynet AppStore. We believe the next generation of Twitter, Medium, TikTok will be built on Skynet.
|
||||
|
||||
By building on the Sia network, Skynet delivers a 10x reduction in storage costs and a 100x reduction in bandwidth costs when compared to centralized providers, without sacrificing performance or reliability. Skynet achieves 1 gigabit per second in download and uploads speeds, with more improvements coming in future releases.
|
||||
|
||||
“For the first time, the decentralized web feels within reach. We’re not talking about a web that is technically feasible yet crippled compared to the centralized alternatives, we are talking about a decentralized web that will become an unstoppable force” said David Vorick, Nebulous CEO and Skynet Lead Developer. “Ten years from now, using centralized applications instead of decentralized applications will feel like using a fax machine instead of email.”
|
||||
|
||||
In addition to the funding news, Nebulous is announcing its rebranding to Skynet to solely focused on developing and growing the Skynet ecosystem. Next-generation applications are already being built on Skynet with more developers joining the community every day. Skynet is different from any platform or technology than has ever been built before. Because of that, we are thrilled to be doubling down on what we know will become the future of the Internet.
|
||||
|
||||
Interested in Skynet? Learn more at siasky.net, join us on Discord, or email us at hello@sia.tech.
|
||||
|
||||
Want to help us re-decentralize the Internet? Nebulous is hiring for positions in marketing and developer evangelism. Learn more about our projects and apply today!
|
||||
|
||||
## About Nebulous
|
||||
|
||||
Nebulous builds uncompromising software infrastructure for the decentralized internet. This includes Sia, the leading decentralized cloud storage platform, and Skynet, a content and application hosting platform.
|
||||
|
||||
Nebulous defines uncompromising infrastructure as scalable, trustless, secure, and – most important – fully decentralized. In a blockchain industry filled with hype but lacking substance, Nebulous stands out as one of the few deeply technical teams that consistently deliver real products with significant potential.
|
||||
|
||||
Nebulous, Inc. was founded in 2014 and is headquartered in Boston. Before the round led by Paradigm, Nebulous was funded by Bain Capital Ventures, A.Capital, Bessemer Venture Partners, Dragonfly Capital Partners, First Star Ventures, and other notable investors.
|
||||
|
||||
## About Paradigm
|
||||
|
||||
Paradigm is a crypto-focused investment firm based in San Francisco founded by Fred Ehrsam and Matt Huang. The firm makes investments focusing on crypto and blockchain technologies from the earliest stages of ideation through maturity. Prior to founding Paradigm, Fred co-founded Coinbase, the largest cryptocurrency company in the US, and Matt was a partner at Sequoia Capital focusing on early-stage venture investments including leading the firm’s cryptocurrency efforts.
|
|
@ -0,0 +1,234 @@
|
|||
---
|
||||
title: Hello World
|
||||
date: "2015-05-01T22:12:03.284Z"
|
||||
description: "Hello World"
|
||||
author: Nicole Tay
|
||||
avatar: ../../team/nicole-tay.png
|
||||
hidden: true
|
||||
---
|
||||
|
||||
This is my first post on my new fake blog! How exciting!
|
||||
|
||||
I'm sure I'll write a lot more interesting things in the future.
|
||||
|
||||
Oh, and here's a great quote from this Wikipedia on
|
||||
[salted duck eggs](https://en.wikipedia.org/wiki/Salted_duck_egg).
|
||||
|
||||
> A salted duck egg is a Chinese preserved food product made by soaking duck
|
||||
> eggs in brine, or packing each egg in damp, salted charcoal. In Asian
|
||||
> supermarkets, these eggs are sometimes sold covered in a thick layer of salted
|
||||
> charcoal paste. The eggs may also be sold with the salted paste removed,
|
||||
> wrapped in plastic, and vacuum packed. From the salt curing process, the
|
||||
> salted duck eggs have a briny aroma, a gelatin-like egg white and a
|
||||
> firm-textured, round yolk that is bright orange-red in color.
|
||||
|
||||
![Chinese Salty Egg](./salty_egg.jpg)
|
||||
|
||||
You can also write code blocks here!
|
||||
|
||||
```js
|
||||
const saltyDuckEgg = "chinese preserved food product";
|
||||
```
|
||||
|
||||
| Number | Title | Year |
|
||||
| :----- | :--------------------------------------- | ---: |
|
||||
| 1 | Harry Potter and the Philosopher’s Stone | 2001 |
|
||||
| 2 | Harry Potter and the Chamber of Secrets | 2002 |
|
||||
| 3 | Harry Potter and the Prisoner of Azkaban | 2004 |
|
||||
|
||||
[View raw (TEST.md)](https://raw.github.com/adamschwartz/github-markdown-kitchen-sink/master/README.md)
|
||||
|
||||
This is a paragraph.
|
||||
|
||||
This is a paragraph.
|
||||
|
||||
# Header 1
|
||||
|
||||
## Header 2
|
||||
|
||||
Header 1
|
||||
========
|
||||
|
||||
Header 2
|
||||
--------
|
||||
|
||||
# Header 1
|
||||
|
||||
## Header 2
|
||||
|
||||
### Header 3
|
||||
|
||||
#### Header 4
|
||||
|
||||
##### Header 5
|
||||
|
||||
###### Header 6
|
||||
|
||||
# Header 1
|
||||
## Header 2
|
||||
### Header 3
|
||||
#### Header 4
|
||||
##### Header 5
|
||||
###### Header 6
|
||||
|
||||
# Header 1
|
||||
|
||||
## Header 2
|
||||
|
||||
### Header 3
|
||||
|
||||
#### Header 4
|
||||
|
||||
##### Header 5
|
||||
|
||||
###### Header 6
|
||||
|
||||
# Header 1 #
|
||||
## Header 2 ##
|
||||
### Header 3 ###
|
||||
#### Header 4 ####
|
||||
##### Header 5 #####
|
||||
###### Header 6 ######
|
||||
|
||||
> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> ## This is a header.
|
||||
>
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> Markdown.generate();
|
||||
|
||||
> ## This is a header.
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> Markdown.generate();
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
* Red
|
||||
* Green
|
||||
* Blue
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
```markdown
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
* Red
|
||||
* Green
|
||||
* Blue
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
```
|
||||
|
||||
- `code goes` here in this line
|
||||
- **bold** goes here
|
||||
|
||||
```markdown
|
||||
- `code goes` here in this line
|
||||
- **bold** goes here
|
||||
```
|
||||
|
||||
1. Buy flour and salt
|
||||
1. Mix together with water
|
||||
1. Bake
|
||||
|
||||
```markdown
|
||||
1. Buy flour and salt
|
||||
1. Mix together with water
|
||||
1. Bake
|
||||
```
|
||||
|
||||
1. `code goes` here in this line
|
||||
1. **bold** goes here
|
||||
|
||||
```markdown
|
||||
1. `code goes` here in this line
|
||||
1. **bold** goes here
|
||||
```
|
||||
|
||||
Paragraph:
|
||||
|
||||
Code
|
||||
|
||||
<!-- -->
|
||||
|
||||
Paragraph:
|
||||
|
||||
Code
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
* * *
|
||||
|
||||
***
|
||||
|
||||
*****
|
||||
|
||||
- - -
|
||||
|
||||
---------------------------------------
|
||||
|
||||
This is [an example](http://example.com "Example") link.
|
||||
|
||||
[This link](http://example.com) has no title attr.
|
||||
|
||||
This is [an example][id] reference-style link.
|
||||
|
||||
[id]: http://example.com "Optional Title"
|
||||
|
||||
This is [an example](http://example.com "Example") link.
|
||||
|
||||
[This link](http://example.com) has no title attr.
|
||||
|
||||
This is [an example] [id] reference-style link.
|
||||
|
||||
[id]: http://example.com "Optional Title"
|
||||
|
||||
_single asterisks_
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
**double underscores**
|
||||
|
||||
*single asterisks*
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
__double underscores__
|
||||
|
||||
This paragraph has some `code` in it.
|
||||
|
||||
This paragraph has some `code` in it.
|
||||
|
||||
![Alt Text](https://placehold.it/200x50 "Image Title")
|
||||
|
||||
![Alt Text](https://placehold.it/200x50 "Image Title")
|
After Width: | Height: | Size: 668 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 37 KiB |
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: Introducing Skynet Labs
|
||||
date: "2021-04-02"
|
||||
description: Nebulous rebrands to Skynet Labs with decentralized internet as the cornerstone of our mission.
|
||||
thumbnail: ./thumbnail.png
|
||||
categories: ["blog"]
|
||||
author: Manasi Vora
|
||||
avatar: ../../team/manasi-vora.png
|
||||
external: https://blog.sia.tech/introducing-skynet-labs-434c852cce07
|
||||
---
|
After Width: | Height: | Size: 103 KiB |
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "Launching the Sia Foundation"
|
||||
date: "2021-01-13"
|
||||
description: Sia v1.5.4 release incorporates the Foundation Hardfork scheduled to activate around midnight, February 3rd, at block height 298,000
|
||||
thumbnail: ./thumbnail.png
|
||||
categories: ["blog"]
|
||||
author: Luke Champine
|
||||
avatar: ../../team/luke-champine.png
|
||||
external: https://blog.sia.tech/launching-the-sia-foundation-ee47dfab4d2c
|
||||
---
|
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: My Second Post!
|
||||
date: "2015-05-06T23:46:37.121Z"
|
||||
description: Wow! I love blogging so much already.
|
||||
author: Daniel Helm
|
||||
avatar: ../../team/daniel-helm.png
|
||||
hidden: true
|
||||
---
|
||||
|
||||
Wow! I love blogging so much already.
|
||||
|
||||
Did you know that "despite its name, salted duck eggs can also be made from
|
||||
chicken eggs, though the taste and texture will be somewhat different, and the
|
||||
egg yolk will be less rich."?
|
||||
([Wikipedia Link](https://en.wikipedia.org/wiki/Salted_duck_egg))
|
||||
|
||||
Yeah, I didn't either.
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
title: New Beginnings
|
||||
date: "2015-05-28T22:40:32.169Z"
|
||||
description: This is a custom description for SEO and Open Graph purposes, rather than the default generated excerpt. Simply add a description field to the frontmatter.
|
||||
author: Karol Wypchlo
|
||||
avatar: ../../team/karol-wypchlo.png
|
||||
hidden: true
|
||||
---
|
||||
|
||||
Far far away, behind the word mountains, far from the countries Vokalia and
|
||||
Consonantia, there live the blind texts. Separated they live in Bookmarksgrove
|
||||
right at the coast of the Semantics, a large language ocean. A small river named
|
||||
Duden flows by their place and supplies it with the necessary regelialia.
|
||||
|
||||
## On deer horse aboard tritely yikes and much
|
||||
|
||||
The Big Oxmox advised her not to do so, because there were thousands of bad
|
||||
Commas, wild Question Marks and devious Semikoli, but the Little Blind Text
|
||||
didn’t listen. She packed her seven versalia, put her initial into the belt and
|
||||
made herself on the way.
|
||||
|
||||
- This however showed weasel
|
||||
- Well uncritical so misled
|
||||
- this is very interesting
|
||||
- Goodness much until that fluid owl
|
||||
|
||||
When she reached the first hills of the **Italic Mountains**, she had a last
|
||||
view back on the skyline of her hometown _Bookmarksgrove_, the headline of
|
||||
[Alphabet Village](http://google.com) and the subline of her own road, the Line
|
||||
Lane. Pityful a rhetoric question ran over her cheek, then she continued her
|
||||
way. On her way she met a copy.
|
||||
|
||||
### Overlaid the jeepers uselessly much excluding
|
||||
|
||||
But nothing the copy said could convince her and so it didn’t take long until a
|
||||
few insidious Copy Writers ambushed her, made her drunk with
|
||||
[Longe and Parole](http://google.com) and dragged her into their agency, where
|
||||
they abused her for their projects again and again. And if she hasn’t been
|
||||
rewritten, then they are still using her.
|
||||
|
||||
> Far far away, behind the word mountains, far from the countries Vokalia and
|
||||
> Consonantia, there live the blind texts. Separated they live in Bookmarksgrove
|
||||
> right at the coast of the Semantics, a large language ocean.
|
||||
|
||||
It is a paradisematic country, in which roasted parts of sentences fly into your
|
||||
mouth. Even the all-powerful Pointing has no control about the blind texts it is
|
||||
an almost unorthographic life One day however a small line of blind text by the
|
||||
name of Lorem Ipsum decided to leave for the far World of Grammar.
|
||||
|
||||
### According a funnily until pre-set or arrogant well cheerful
|
||||
|
||||
The Big Oxmox advised her not to do so, because there were thousands of bad
|
||||
Commas, wild Question Marks and devious Semikoli, but the Little Blind Text
|
||||
didn’t listen. She packed her seven versalia, put her initial into the belt and
|
||||
made herself on the way.
|
||||
|
||||
1. So baboon this
|
||||
2. Mounted militant weasel gregariously admonishingly straightly hey
|
||||
3. Dear foresaw hungry and much some overhung
|
||||
4. Rash opossum less because less some amid besides yikes jeepers frenetic
|
||||
impassive fruitlessly shut
|
||||
|
||||
When she reached the first hills of the Italic Mountains, she had a last view
|
||||
back on the skyline of her hometown Bookmarksgrove, the headline of Alphabet
|
||||
Village and the subline of her own road, the Line Lane. Pityful a rhetoric
|
||||
question ran over her cheek, then she continued her way. On her way she met a
|
||||
copy.
|
||||
|
||||
> The copy warned the Little Blind Text, that where it came from it would have
|
||||
> been rewritten a thousand times and everything that was left from its origin
|
||||
> would be the word "and" and the Little Blind Text should turn around and
|
||||
> return to its own, safe country.
|
||||
|
||||
But nothing the copy said could convince her and so it didn’t take long until a
|
||||
few insidious Copy Writers ambushed her, made her drunk with Longe and Parole
|
||||
and dragged her into their agency, where they abused her for their projects
|
||||
again and again. And if she hasn’t been rewritten, then they are still using
|
||||
her. Far far away, behind the word mountains, far from the countries Vokalia and
|
||||
Consonantia, there live the blind texts.
|
||||
|
||||
#### Silent delightfully including because before one up barring chameleon
|
||||
|
||||
Separated they live in Bookmarksgrove right at the coast of the Semantics, a
|
||||
large language ocean. A small river named Duden flows by their place and
|
||||
supplies it with the necessary regelialia. It is a paradisematic country, in
|
||||
which roasted parts of sentences fly into your mouth.
|
||||
|
||||
Even the all-powerful Pointing has no control about the blind texts it is an
|
||||
almost unorthographic life One day however a small line of blind text by the
|
||||
name of Lorem Ipsum decided to leave for the far World of Grammar. The Big Oxmox
|
||||
advised her not to do so, because there were thousands of bad Commas, wild
|
||||
Question Marks and devious Semikoli, but the Little Blind Text didn’t listen.
|
||||
|
||||
##### Wherever far wow thus a squirrel raccoon jeez jaguar this from along
|
||||
|
||||
She packed her seven versalia, put her initial into the belt and made herself on
|
||||
the way. When she reached the first hills of the Italic Mountains, she had a
|
||||
last view back on the skyline of her hometown Bookmarksgrove, the headline of
|
||||
Alphabet Village and the subline of her own road, the Line Lane. Pityful a
|
||||
rhetoric question ran over her cheek, then she continued her way. On her way she
|
||||
met a copy.
|
||||
|
||||
###### Slapped cozy a that lightheartedly and far
|
||||
|
||||
The copy warned the Little Blind Text, that where it came from it would have
|
||||
been rewritten a thousand times and everything that was left from its origin
|
||||
would be the word "and" and the Little Blind Text should turn around and return
|
||||
to its own, safe country. But nothing the copy said could convince her and so it
|
||||
didn’t take long until a few insidious Copy Writers ambushed her, made her drunk
|
||||
with Longe and Parole and dragged her into their agency, where they abused her
|
||||
for their projects again and again.
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title: "Skynet Introduces Premium Accounts, Sets the Foundation for New Creator Economies"
|
||||
date: "2021-03-22"
|
||||
description: "Premium accounts support creators while giving users up to 20 TB of data storage per month and other perks."
|
||||
author: "Skynet Labs"
|
||||
categories: ["press release"]
|
||||
avatar: "../images/skynet-avatar.png"
|
||||
thumbnail: "../images/press-release.png"
|
||||
---
|
||||
|
||||
**BOSTON, Massachusetts, March 22, 2021** — Skynet Labs introduces new paid accounts and sets the stage for recursive content monetization. To celebrate, Skynet is giving out premium accounts to the first 100 users who sign up at siasky.net. The giveaway includes 1 TB of storage and 3 months of censorship-resistant file pinning. Skynet is a decentralized CDN and foundation for a new, decentralized internet. It is an open protocol for building decentralized applications, and is built on top of Sia, a decentralized storage network.
|
||||
|
||||
Soon, creators will be able to set the price per view or download of their work and earn directly from their blogs, photos, and videos in real time. In this way, recursive content monetization reduces artists’ dependency on traditional advertising to make ends meet. When users pay for premium accounts in fiat, they provide a steady revenue stream from which to pay out content creators.
|
||||
|
||||
Application developers will also benefit from content monetization. Like content creators, developers can attach price tags to their applications. Per David Vorick, Skynet Labs CEO and Lead Developer, “We believe that developers and content creators alike should be able to earn income off of their hard work so long as they have users that appreciate what they do.”
|
||||
|
||||
Skynet Labs has always been committed to the freedom of expression, information, and importantly, access. Therefore, Skynet’s Free account tier supporting up to 100 GB of data, seeks to ensure that financial barriers never prohibit users and developers from participating in the Skynet ecosystem. Once a user meets their data cap, service on Skynet will continue but at reduced speeds, in a way similar to data plans for smartphones.
|
||||
|
||||
Overall, users can opt for one of three paid tiers: $5/month with 1 TB, $20/month with 4 TB, or \$80/month with 20 TB of data. Skynet Premium also comes with significant performance boosts: users will be able to pin content and browse Skynet faster, in particular any pages with monetized content. The benefits of a premium account are not purely in performance—these users are actively fueling a new creator economy, and a revolution that gives creators everywhere the power they deserve.
|
||||
|
||||
## About Skynet Labs
|
||||
|
||||
Skynet Labs, formerly known as Nebulous, builds uncompromising software infrastructure for the decentralized internet. This includes Sia, the leading decentralized cloud storage platform, and Skynet, a content hosting and application development platform.
|
||||
|
||||
Skynet Labs defines uncompromising infrastructure as scalable, trustless, secure, and – most importantly – fully decentralized. In a blockchain industry filled with hype but lacking substance, Skynet Labs stands out as one of the few deeply technical teams that consistently delivers real products with significant potential.
|
||||
|
||||
Nebulous, Inc. was founded in 2014 and is backed by Paradigm, Bain Capital Ventures, A.Capital, Bessemer Venture Partners, Dragonfly Capital Partners, First Star Ventures, and other notable investors.
|
||||
Learn more at siasky.net, join us on Discord, and email us at hello@sia.tech.
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
title: "Skynet Announces SkyDB, Unlocking a Fully Decentralized Internet"
|
||||
date: "2020-10-15"
|
||||
description: "SkyDB enables decentralized social media to take on `The Social Dilemma`"
|
||||
author: "Skynet Labs"
|
||||
categories: ["press release"]
|
||||
avatar: "../images/skynet-avatar.png"
|
||||
thumbnail: "../images/press-release.png"
|
||||
---
|
||||
|
||||
**Boston, MA – October 15th, 2020** — Skynet Labs, the company building the Sia decentralized cloud storage platform and the Skynet application hosting platform, today announced the launch of SkyDB, a framework that allows developers to build feature-complete applications that compete with the likes of Youtube, Twitter, Instagram, and Tiktok.
|
||||
|
||||
The fabric of our society and the way we interact with each other has been heavily influenced and altered by the rise of social media platforms. Biased algorithms amplify stereotypes, constant streams of content compete for our attention, and manipulated narratives wedge digital divides across political ideologies and cultural identities. As pertinently pointed out by the popular Social Dilemma documentary, “We have moved from a tools-based technology environment to an addiction and manipulation based technology environment"
|
||||
|
||||
SkyDB enables developers to realize the full potential of a Free Internet. Building these Web3 applications not only has benefits of privacy and control over one’s data but it ushers innovation currently impossible in the siloed centralized web of today. SkyDB is a framework that allows users to create decentralized accounts and store mutable data in those accounts which can be accessed globally from any device. The user does not need to sync any blockchains or run any special software — a normal web browser is sufficient. For more details on the inner workings of SkyDB and the potential it unlocks, check out our latest blog post.
|
||||
|
||||
“Today is a turning point in history where the decentralized web starts to eat the centralized web,” said David Vorick, Skynet Labs CEO and lead developer. “Skynet gives developers more tools to create better experiences for users. Skynet in many senses is the first true cloud, where all data is available everywhere, regardless of the original application.”
|
||||
|
||||
Skynet was launched back in February 2020 and since then has seen accelerated growth in developer interest and usage. Users around the world have uploaded more than 2.5 million files amounting to 15+ TeraBytes of data using Skynet. In October, Skynet crossed a record-high of 150,000 downloads in a single day.
|
||||
|
||||
A thriving community of developers has built over 150 applications in the span of a few months including a Video Streaming app SkyLive, Blogging apps like Wakio and Skyblog Builder, Video & Image gallery app SkyGallery, a Decentralized AppStore Skydroid. The full list of Skynet Apps can be explored at the Skynet AppStore, and an English language Wikipedia clone.
|
||||
|
||||
“Next-generation applications are already being built on Skynet with more developers joining the community every day,” said Manasi Vora, Skynet Labs’ VP Strategy & Operations. “Skynet shines in how its easy to use not just for developers but also for the end-users, a rarity in the blockchain space.”
|
||||
|
||||
By building on the Sia network, Skynet delivers a 10x reduction in storage costs and a 100x reduction in bandwidth costs when compared to centralized providers, without sacrificing performance or reliability. Skynet achieves 1 gigabit per second in download and uploads speeds, with more improvements coming in future releases.
|
||||
|
||||
Interested in Skynet? Learn more at Siasky.net join us on Discord, and email us at hello@sia.tech.
|
||||
|
||||
## About Skynet Labs
|
||||
|
||||
Skynet Labs, previously known as Nebulous, builds uncompromising software infrastructure for the decentralized internet. This includes Sia, the leading decentralized cloud storage platform, and Skynet, a content and application hosting platform.
|
||||
|
||||
Skynet Labs defines uncompromising infrastructure as scalable, trustless, secure, and – most important – fully decentralized. In a blockchain industry filled with hype but lacking substance, Skynet Labs stands out as one of the few deeply technical teams that consistently deliver real products with significant potential.
|
||||
|
||||
Nebulous, Inc. was founded in 2014 and is headquartered in Boston. It is funded by Paradigm, Bain Capital Ventures, A.Capital, Bessemer Venture Partners, Dragonfly Capital Partners, First Star Ventures, and other notable investors.
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: "Sia Announces Skynet, the Storage Foundation for a Free Internet"
|
||||
description: "Skynet is available with Sia version 1.4.3 and ready to use today!"
|
||||
date: "2020-02-18"
|
||||
author: "Skynet Labs"
|
||||
categories: ["press release"]
|
||||
avatar: "../images/skynet-avatar.png"
|
||||
thumbnail: "../images/press-release.png"
|
||||
---
|
||||
|
||||
**Boston, MA – February 18, 2020** — Nebulous, the company building the Sia decentralized cloud storage network, today announced the launch of Skynet, a decentralized CDN and file sharing platform for application developers. Skynet enables high speed, low cost, and superior infrastructure to serve as the storage foundation for a free Internet.
|
||||
|
||||
Today’s decentralized applications (dapps) largely rely on centralized data storage providers like Amazon, due to the lack of reliable, fast, and production-ready decentralized alternatives. This makes it difficult for developers to build truly decentralized applications and prevents the dapp ecosystem from realizing the real potential of a Free Internet.
|
||||
|
||||
Skynet provides an easy-to-use data storage and publishing mechanism on which developers can build decentralized applications. With a simple API and SDKs for popular programming languages, Skynet empowers developers to easily integrate decentralized storage into their applications. Importantly, end-users can directly access files on Skynet without needing to run full nodes or deal with cryptocurrencies.
|
||||
|
||||
By building on the Sia Network, Skynet delivers a 10x reduction in storage costs and a 100x reduction in bandwidth costs when compared to centralized providers, without sacrificing performance or reliability. Amazingly, Skynet achieves 1 gigabit per second in download and uploads speeds, with more improvements coming in future releases.
|
||||
|
||||
“After seven years of nonstop work, applications built on decentralized storage are finally viable. I can say without a doubt that Skynet is the most powerful tech we've ever built” said David Vorick, Nebulous CEO and Sia Lead Developer. “Skynet makes it possible for content and applications to be deployed to a decentralized network just in seconds and be immediately available to everyone across the world.”
|
||||
|
||||
Our vision for Skynet involves supporting decentralized content publishing. Whether through news articles, blog posts, music, or video, Nebulous envisions Skynet as a decentralized and censorship-resistant foundation for content creators to deliver media their audience cares about. No more de-platforming, no more exploitation.
|
||||
|
||||
“One place where Skynet shines is speed. Page loading is almost instant. Deployment to Skynet is also almost instant. We’ve demonstrated that decentralized storage can be as fast as its centralized competitors” said Manasi Vora, Nebulous’ Head of Product Strategy. “With storage and bandwidth prices so low, we expect Skynet to enable previously unimaginable applications and spark a renaissance in media-heavy applications.”
|
||||
|
||||
Since Sia’s launch in 2015, users have stored over 4 PB of data across over 1 million storage smart contracts. Currently, the Sia network has 2.2 PB of available storage capacity and Sia software has been downloaded over 1 million times. Sia has a thriving community of third-party developers who have launched file sharing websites like PixelDrain and Storewise, cloud offerings like Filebase and Arzen,and companion apps like Decentralizer and SiaCentral.
|
||||
|
||||
Interested in Skynet? Learn more at Siasky.net join us on Discord, and email us at hello@sia.tech.
|
||||
|
||||
Want to help us re-decentralize the Internet? Nebulous is hiring for positions in engineering and operations. Learn more about our projects and apply today!
|
||||
|
||||
## About Skynet Labs
|
||||
|
||||
Nebulous builds uncompromising blockchain hardware and software infrastructure for the decentralized internet. This includes Sia, the leading decentralized cloud storage platform, and Obelisk, a producer of blockchain-related hardware.
|
||||
|
||||
Nebulous defines uncompromising infrastructure as scalable, trustless, secure, and – most important – fully decentralized. In a blockchain industry filled with hype but lacking substance, Nebulous stands out as one of the few deeply technical teams that consistently delivers real products with significant potential.
|
||||
|
||||
Nebulous, Inc. was founded in 2014 and is headquartered in Boston. Nebulous is funded by Bain Capital Ventures, A.Capital, Raptor Group, First Star Ventures, and other notable investors.
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "Skynet Community Update — March 2021"
|
||||
date: "2021-03-10"
|
||||
description: Get updated on the Skynet and Sia ecosystem for the past few months.
|
||||
thumbnail: ./thumbnail.png
|
||||
categories: ["blog"]
|
||||
author: Steve Funk
|
||||
avatar: ../../team/steve-funk.png
|
||||
external: https://blog.sia.tech/skynet-community-update-march-2021-960426c9abce
|
||||
---
|
After Width: | Height: | Size: 75 KiB |
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: "The Skynet License"
|
||||
date: "2021-03-18"
|
||||
description: New source code license by Skynet Labs that enables a sustainable business model while empowering freedom
|
||||
thumbnail: ./thumbnail.png
|
||||
categories: ["blog"]
|
||||
author: David Vorick
|
||||
avatar: ../../team/david-vorick.png
|
||||
external: https://blog.sia.tech/the-skynet-license-cf62d5c358c5
|
||||
---
|
After Width: | Height: | Size: 3.2 MiB |
|
@ -0,0 +1,19 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80">
|
||||
<defs>
|
||||
<filter id="1-a">
|
||||
<feColorMatrix in="SourceGraphic" values="0 0 0 0 0.050980 0 0 0 0 0.050980 0 0 0 0 0.050980 0 0 0 1.000000 0"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#00C65E" d="M29.031876,20.9098666 L28.9376,20.9996 L26.0006,32.418457 L26.0002217,47.4850772 C15.5253909,39.5307935 9.94339742,30.0594707 13.1535,24.4995 C15.3983377,20.6113901 21.4491262,19.4904168 29.031876,20.9098666 Z"/>
|
||||
<g filter="url(#1-a)">
|
||||
<g transform="translate(10 9)">
|
||||
<path stroke="#222829" stroke-width="2" d="M25.1486,1.9116 C26.6606,0.6766 28.2946,-0.0004 30.0006,-0.0004 C37.7326,-0.0004 44.0006,13.8786 44.0006,30.9996 C44.0006,48.1206 37.7326,61.9996 30.0006,61.9996 C22.2676,61.9996 16.0006,48.1206 16.0006,30.9996 C16.0006,23.8406 17.0956,17.2476 18.9376,11.9996"/>
|
||||
<path stroke="#222829" stroke-width="2" d="M57.6955,41.9185 C57.8795,43.6185 57.6145,45.1705 56.8465,46.4995 C52.9805,53.1955 37.8275,51.6855 23.0005,43.1245 C8.1735,34.5645 -0.7125,22.1955 3.1535,15.4995 C7.0195,8.8035 22.1735,10.3145 37.0005,18.8745 C43.2405,22.4785 48.4285,26.7565 52.0565,31.0025"/>
|
||||
<path stroke="#222829" stroke-width="2" d="M2.3049,41.9155 C2.1199,43.6165 2.3859,45.1695 3.1539,46.4995 C7.0199,53.1955 22.1729,51.6855 36.9999,43.1245 C51.8269,34.5645 60.7129,22.1955 56.8469,15.4995 C52.9809,8.8035 37.8269,10.3145 22.9999,18.8745 C16.7599,22.4785 11.5729,26.7545 7.9459,30.9995"/>
|
||||
<path stroke="#222829" stroke-width="2" d="M6.0002 38.9995C6.0002 40.6565 4.6562 41.9995 3.0002 41.9995 1.3442 41.9995.0002 40.6565.0002 38.9995.0002 37.3435 1.3442 35.9995 3.0002 35.9995 4.6562 35.9995 6.0002 37.3435 6.0002 38.9995zM60.0002 38.9995C60.0002 40.6565 58.6562 41.9995 57.0002 41.9995 55.3442 41.9995 54.0002 40.6565 54.0002 38.9995 54.0002 37.3435 55.3442 35.9995 57.0002 35.9995 58.6562 35.9995 60.0002 37.3435 60.0002 38.9995zM26.0002 3.9995C26.0002 5.6565 24.6562 6.9995 23.0002 6.9995 21.3442 6.9995 20.0002 5.6565 20.0002 3.9995 20.0002 2.3435 21.3442.9995 23.0002.9995 24.6562.9995 26.0002 2.3435 26.0002 3.9995zM21.0002 38.9995C21.0002 32.9995 27.0002 31.9995 27.0002 31.9995M39.0002 38.9995C39.0002 32.9995 33.0002 31.9995 33.0002 31.9995"/>
|
||||
<path stroke="#222829" stroke-width="2" d="M35.0002,26.4995 C35.0002,29.9995 33.0372,32.9995 30.0002,32.9995 C26.9632,32.9995 25.0002,29.9995 25.0002,26.4995 C25.0002,22.9995 26.0002,20.9995 30.0002,20.9995 C34.0002,20.9995 35.0002,22.9995 35.0002,26.4995 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,6 @@
|
|||
- cards:
|
||||
- title: Own your data
|
||||
description: No one owns or controls your account data except for you. Ownership extends to original blogs, music, and videos too. This is all possible through decentralized apps built on decentralized storage.
|
||||
image: ./assets/own-your-data.svg
|
||||
- title: Censorship-resistant content
|
||||
description: Today, censorship can come arbitrarily, top-down, and as a tool to silence expression. Post and share content on Skynet, or use Skynet as a fail-over for your website if a service provider goes down.
|
|
@ -0,0 +1,92 @@
|
|||
- name: David Vorick
|
||||
position: CEO and Lead Developer
|
||||
image: ./team/david-vorick.png
|
||||
social:
|
||||
github: https://github.com/DavidVorick
|
||||
gitlab: https://gitlab.com/DavidVorick
|
||||
twitter: https://twitter.com/davidvorick
|
||||
|
||||
- name: Chris Schinnerl
|
||||
position: VP of Technology
|
||||
image: ./team/chris-schinnerl.png
|
||||
social:
|
||||
github: https://github.com/ChrisSchinnerl
|
||||
gitlab: https://gitlab.com/ChrisSchinnerl
|
||||
twitter: https://twitter.com/ChrisSchinnerl
|
||||
|
||||
- name: Steve Funk
|
||||
position: Head of Support
|
||||
image: ./team/steve-funk.png
|
||||
social:
|
||||
linkedin: https://www.linkedin.com/in/stevengfunk
|
||||
|
||||
- name: Matt Sevey
|
||||
position: Engineering Manager
|
||||
image: ./team/matt-sevey.png
|
||||
social:
|
||||
github: https://github.com/MSevey
|
||||
gitlab: https://gitlab.com/MSevey
|
||||
linkedin: https://www.linkedin.com/in/sevey
|
||||
twitter: https://twitter.com/MJSevey
|
||||
|
||||
- name: Manasi Vora
|
||||
position: VP of Strategy and Ops
|
||||
image: ./team/manasi-vora.png
|
||||
social:
|
||||
linkedin: https://linkedin.com/in/manasi-vora-cfa-bb9a1715
|
||||
twitter: https://twitter.com/manasilvora
|
||||
|
||||
- name: PJ Brone
|
||||
position: Core Developer
|
||||
image: ./team/pj-brone.png
|
||||
social:
|
||||
github: https://github.com/peterjan
|
||||
gitlab: https://gitlab.com/pjbrone
|
||||
linkedin: https://www.linkedin.com/in/peterjanbrone
|
||||
twitter: https://twitter.com/peterjanbrone
|
||||
|
||||
- name: Marcin Swieczkowski
|
||||
position: Core Developer
|
||||
image: ./team/marcin-swieczkowski.png
|
||||
social:
|
||||
github: https://github.com/m-cat
|
||||
gitlab: https://gitlab.com/m-cat
|
||||
|
||||
- name: Karol Wypchlo
|
||||
position: Full Stack Developer
|
||||
image: ./team/karol-wypchlo.png
|
||||
social:
|
||||
github: https://github.com/kwypchlo
|
||||
gitlab: https://gitlab.com/kwypchlo
|
||||
linkedin: https://www.linkedin.com/in/karolwypchlo/
|
||||
twitter: https://twitter.com/kwypchlo
|
||||
|
||||
- name: Ivaylo Novakov
|
||||
position: Core Developer
|
||||
image: ./team/ivaylo-novakov.png
|
||||
social:
|
||||
github: https://github.com/ro-tex
|
||||
gitlab: https://gitlab.com/ro-tex
|
||||
linkedin: https://www.linkedin.com/in/inovakov/
|
||||
twitter: https://twitter.com/inovakov
|
||||
|
||||
- name: Filip Rysavy
|
||||
position: Testing Developer
|
||||
image: ./team/filip-rysavy.png
|
||||
social:
|
||||
linkedin: https://www.linkedin.com/in/filiprysavy/
|
||||
|
||||
- name: Nicole Tay
|
||||
position: Head of Marketing
|
||||
image: ./team/nicole-tay.png
|
||||
social:
|
||||
linkedin: https://www.linkedin.com/in/nicolehtay/
|
||||
twitter: https://twitter.com/NicoleHTay
|
||||
|
||||
- name: Daniel Helm
|
||||
position: Developer Evangelist
|
||||
image: ./team/daniel-helm.png
|
||||
social:
|
||||
github: https://github.com/dghelm
|
||||
linkedin: https://www.linkedin.com/in/dghelm/
|
||||
twitter: https://twitter.com/danielgileshelm
|
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 7.9 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Implement Gatsby's Browser APIs in this file.
|
||||
*
|
||||
* See: https://www.gatsbyjs.com/docs/browser-apis/
|
||||
*/
|
||||
|
||||
import "normalize.css";
|
||||
import "@fontsource/sora/300.css"; // light
|
||||
import "@fontsource/sora/400.css"; // normal
|
||||
import "@fontsource/sora/500.css"; // medium
|
||||
import "@fontsource/sora/600.css"; // semibold
|
||||
import "@fontsource/source-sans-pro/400.css"; // normal
|
||||
import "@fontsource/source-sans-pro/600.css"; // semibold
|
||||
import "./src/styles/global.css";
|
||||
|
||||
import * as React from "react";
|
||||
import Layout from "./src/components/Layout";
|
||||
|
||||
export const wrapPageElement = ({ element, props }) => {
|
||||
// props provide same data to Layout as Page element will get
|
||||
// including location, data, etc - you don't need to pass it
|
||||
return <Layout {...props}>{element}</Layout>;
|
||||
};
|
|
@ -0,0 +1,122 @@
|
|||
const { defaultIcons } = require("gatsby-plugin-manifest/common");
|
||||
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: `Skynet`,
|
||||
description: `Skynet is a decentralized file sharing and content distribution protocol`,
|
||||
author: `Skynet Labs`,
|
||||
siteUrl: `https://siasky.net`,
|
||||
image: `https://siasky.net/icons/icon-512x512.png`,
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
name: `images`,
|
||||
path: `${__dirname}/src/images`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
name: `src`,
|
||||
path: `${__dirname}/src/`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
name: `data`,
|
||||
path: `${__dirname}/data/`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `${__dirname}/data/news`,
|
||||
name: `news`,
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-postcss`,
|
||||
`gatsby-plugin-react-helmet`,
|
||||
`gatsby-plugin-image`,
|
||||
`gatsby-plugin-sharp`,
|
||||
`gatsby-plugin-react-svg`,
|
||||
`gatsby-plugin-robots-txt`,
|
||||
`gatsby-transformer-sharp`,
|
||||
`gatsby-transformer-json`,
|
||||
`gatsby-transformer-yaml`,
|
||||
{
|
||||
resolve: `gatsby-transformer-remark`,
|
||||
options: {
|
||||
plugins: [
|
||||
{
|
||||
resolve: `gatsby-remark-classes`,
|
||||
options: {
|
||||
classMap: {
|
||||
heading: "font-semibold text-palette-600",
|
||||
paragraph: "font-content text-base text-palette-400",
|
||||
strong: "font-semibold",
|
||||
link: "text-primary hover:underline transition-colors duration-200",
|
||||
"heading[depth=1]": "text-4xl",
|
||||
"heading[depth=2]": "text-3xl",
|
||||
"paragraph + paragraph": "mt-8",
|
||||
"paragraph + heading": "mt-20",
|
||||
"heading + paragraph": "mt-12",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-remark-images`,
|
||||
options: {
|
||||
maxWidth: 630,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-remark-responsive-iframe`,
|
||||
options: {
|
||||
wrapperStyle: `margin-bottom: 1.0725rem`,
|
||||
},
|
||||
},
|
||||
`gatsby-remark-prismjs`,
|
||||
`gatsby-remark-copy-linked-files`,
|
||||
`gatsby-remark-smartypants`,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-plugin-manifest`,
|
||||
options: {
|
||||
name: `Skynet`,
|
||||
short_name: `Skynet`,
|
||||
start_url: `/`,
|
||||
background_color: `#f1f7f2`,
|
||||
theme_color: `#f1f7f2`,
|
||||
display: `minimal-ui`,
|
||||
icon: `src/images/logo.svg`, // This path is relative to the root of the site.
|
||||
icons: [
|
||||
...defaultIcons,
|
||||
// when we're serving content from the portal on our pathnames that do not have
|
||||
// favicon defined (basically all non-html content), we want the browsers to be
|
||||
// able to fall back to favicon.ico (firefox does that)
|
||||
{
|
||||
src: `favicon.ico`,
|
||||
sizes: `32x32`,
|
||||
type: `image/x-icon`,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: "gatsby-plugin-matomo",
|
||||
options: {
|
||||
siteId: 3,
|
||||
matomoUrl: "https://surveillance.sia.tech",
|
||||
siteUrl: "https://siasky.net",
|
||||
},
|
||||
},
|
||||
],
|
||||
// mapping: {
|
||||
// "MarkdownRemark.frontmatter.author": `teamYaml`,
|
||||
// },
|
||||
};
|
|
@ -0,0 +1,122 @@
|
|||
const path = require(`path`);
|
||||
const { createFilePath } = require(`gatsby-source-filesystem`);
|
||||
|
||||
exports.onCreateWebpackConfig = ({ actions }) => {
|
||||
actions.setWebpackConfig({
|
||||
resolve: {
|
||||
fallback: {
|
||||
crypto: require.resolve("crypto-browserify"),
|
||||
stream: require.resolve("stream-browserify"),
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
exports.createPages = async ({ graphql, actions, reporter }) => {
|
||||
const { createPage } = actions;
|
||||
|
||||
// Define a template for news post
|
||||
const PostTemplate = path.resolve(`./src/templates/news-post.js`);
|
||||
|
||||
// Get all markdown news posts sorted by date and all possible authors
|
||||
const result = await graphql(
|
||||
`
|
||||
{
|
||||
allMarkdownRemark(
|
||||
sort: { fields: [frontmatter___date], order: ASC }
|
||||
filter: { frontmatter: { external: { eq: null } } }
|
||||
) {
|
||||
nodes {
|
||||
id
|
||||
fields {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
if (result.errors) {
|
||||
reporter.panicOnBuild(`There was an error loading your news posts`, result.errors);
|
||||
return;
|
||||
}
|
||||
|
||||
const posts = result.data.allMarkdownRemark.nodes;
|
||||
|
||||
// Create news posts pages
|
||||
// But only if there's at least one markdown file found at "/data/news" (defined in gatsby-config.js)
|
||||
// `context` is available in the template as a prop and as a variable in GraphQL
|
||||
|
||||
if (posts.length > 0) {
|
||||
posts.forEach((post, index) => {
|
||||
const previousPostId = index === 0 ? null : posts[index - 1].id;
|
||||
const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id;
|
||||
|
||||
createPage({
|
||||
path: post.fields.slug,
|
||||
component: PostTemplate,
|
||||
context: {
|
||||
id: post.id,
|
||||
previousPostId,
|
||||
nextPostId,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.onCreateNode = ({ node, actions, getNode }) => {
|
||||
const { createNodeField } = actions;
|
||||
|
||||
if (node.internal.type === `MarkdownRemark`) {
|
||||
const value = createFilePath({ node, getNode });
|
||||
|
||||
createNodeField({
|
||||
name: `slug`,
|
||||
node,
|
||||
value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.createSchemaCustomization = ({ actions }) => {
|
||||
const { createTypes } = actions;
|
||||
|
||||
// Explicitly define the siteMetadata {} object
|
||||
// This way those will always be defined even if removed from gatsby-config.js
|
||||
|
||||
// Also explicitly define the Markdown frontmatter
|
||||
// This way the "MarkdownRemark" queries will return `null` even when no
|
||||
// news posts are stored inside "/data/news" instead of returning an error
|
||||
createTypes(`
|
||||
type SiteSiteMetadata {
|
||||
author: String
|
||||
siteUrl: String
|
||||
social: Social
|
||||
}
|
||||
type Author {
|
||||
name: String
|
||||
summary: String
|
||||
}
|
||||
type Social {
|
||||
twitter: String
|
||||
}
|
||||
type MarkdownRemark implements Node {
|
||||
frontmatter: Frontmatter
|
||||
fields: Fields
|
||||
}
|
||||
type Frontmatter {
|
||||
title: String
|
||||
description: String
|
||||
date: Date @dateformat
|
||||
author: String
|
||||
external: String
|
||||
hidden: Boolean
|
||||
categories: [String]
|
||||
}
|
||||
type Fields {
|
||||
slug: String
|
||||
}
|
||||
`);
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
|
||||
*
|
||||
* See: https://www.gatsbyjs.com/docs/ssr-apis/
|
||||
*/
|
||||
|
||||
// You can delete this file if you're not using it
|