mirror of
https://github.com/zhigang1992/notion-api-worker.git
synced 2026-01-12 17:32:42 +08:00
Implement pages, tables & users; WIP
Co-authored-by: Timo <timo.lins@gmail.com>
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,2 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
worker
|
||||
wrangler.toml
|
||||
36
README.md
36
README.md
@@ -1,2 +1,36 @@
|
||||
# notion-cloudflare-worker
|
||||
|
||||
|
||||
A serverless layer on top of the private Notion API. It leverages [Cloudflare Workers](https://workers.cloudflare.com/), to provide fast and easy access to all your Notion content.
|
||||
|
||||
_This package might become obsolete, once the official Notion API arrives._
|
||||
|
||||
## Features
|
||||
|
||||
🍭 **Easy to use** – Receive Notion data with a single GET request
|
||||
✨ **Fast CDN** – Leverage the global Cloudflare CDN
|
||||
🛫 **CORS Friendly** – Access your data where you need it
|
||||
🗄 **Table Access** – Get structured data from tables & databases
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Use a table to manage posts for your blog
|
||||
|
||||
## Endpoints
|
||||
|
||||
We provide a hosted version of this project on [https://notion.splitbee.io/](https://notion.splitbee.io/). You can also [host your own](https://workers.cloudflare.com/). Cloudflare offers a generous free plan with up to 100,000 request per day.
|
||||
|
||||
### Get data from a page - `/v1/page/<PAGE_ID>`
|
||||
|
||||
[Example](https://notion.splitbee.io/v1/page/2e22de6b770e4166be301490f6ffd420)
|
||||
|
||||
Returns all block data for a given page.
|
||||
For example, you can render this data with [`react-notion`](https://github.com/splitbee/react-notion).
|
||||
|
||||
### Get parsed data from table `/v1/table/<PAGE_ID>`
|
||||
|
||||
[Example](https://notion.splitbee.io/v1/page/2e22de6b770e4166be301490f6ffd420)
|
||||
|
||||
## Credits
|
||||
|
||||
- [Timo Lins](https://timo.sh) – Idea, Documentation
|
||||
- [Tobias Lins](https://tobi.sh) – Code
|
||||
|
||||
22
package.json
22
package.json
@@ -1,7 +1,21 @@
|
||||
{
|
||||
"name": "notion-cloudflare-worker",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "Tobias Lins",
|
||||
"license": "MIT"
|
||||
"version": "0.1.0",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"dev": "wrangler preview --watch",
|
||||
"deploy": "wrangler publish -e production"
|
||||
},
|
||||
"dependencies": {
|
||||
"tiny-request-router": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^1.0.9",
|
||||
"@types/node": "^13.13.1",
|
||||
"prettier": "^2.0.4",
|
||||
"ts-loader": "^7.0.1",
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
}
|
||||
|
||||
94
src/api/notion.ts
Normal file
94
src/api/notion.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { resolve } from "dns";
|
||||
|
||||
const NOTION_API = "https://www.notion.so/api/v3";
|
||||
|
||||
type JSONData =
|
||||
| null
|
||||
| boolean
|
||||
| number
|
||||
| string
|
||||
| JSONData[]
|
||||
| { [prop: string]: JSONData };
|
||||
|
||||
type INotionParams = {
|
||||
resource: string;
|
||||
body: JSONData;
|
||||
};
|
||||
|
||||
const loadPageChunkBody = {
|
||||
limit: 999,
|
||||
cursor: { stack: [] },
|
||||
chunkNumber: 0,
|
||||
verticalColumns: false,
|
||||
};
|
||||
|
||||
const fetchNotionData = async ({ resource, body }: INotionParams) => {
|
||||
const res = await fetch(`${NOTION_API}/${resource}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
//cf: {}
|
||||
});
|
||||
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const fetchPageById = async (pageId: string) => {
|
||||
const res = await fetchNotionData({
|
||||
resource: "loadPageChunk",
|
||||
body: {
|
||||
pageId,
|
||||
...loadPageChunkBody,
|
||||
},
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
const queryCollectionBody = {
|
||||
query: { aggregations: [{ property: "title", aggregator: "count" }] },
|
||||
loader: {
|
||||
type: "table",
|
||||
limit: 999,
|
||||
searchQuery: "",
|
||||
userTimeZone: "Europe/Vienna",
|
||||
userLocale: "en",
|
||||
loadContentCover: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const fetchTableData = async (
|
||||
collectionId: string,
|
||||
collectionViewId: string
|
||||
) => {
|
||||
const table = await fetchNotionData({
|
||||
resource: "queryCollection",
|
||||
body: {
|
||||
collectionId,
|
||||
collectionViewId,
|
||||
...queryCollectionBody,
|
||||
},
|
||||
});
|
||||
return table;
|
||||
};
|
||||
|
||||
export const fetchNotionUser = async (
|
||||
userIds: string[]
|
||||
): Promise<{ id: string; full_name: string }[]> => {
|
||||
const users = await fetchNotionData({
|
||||
resource: "getRecordValues",
|
||||
body: {
|
||||
requests: userIds.map((id) => ({ id, table: "notion_user" })),
|
||||
},
|
||||
});
|
||||
|
||||
return users.results.map((u: any) => {
|
||||
const user = {
|
||||
id: u.value.id,
|
||||
full_name: u.value.given_name + " " + u.value.family_name,
|
||||
};
|
||||
return user;
|
||||
});
|
||||
};
|
||||
86
src/api/types.ts
Normal file
86
src/api/types.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
type BoldFormatType = ["b"];
|
||||
type ItalicFormatType = ["i"];
|
||||
type StrikeFormatType = ["s"];
|
||||
type CodeFormatType = ["c"];
|
||||
type LinkFormatType = ["a", string];
|
||||
type DateFormatType = [
|
||||
"d",
|
||||
{
|
||||
type: "date";
|
||||
start_date: string;
|
||||
date_format: string;
|
||||
}
|
||||
];
|
||||
type UserFormatType = ["u", string];
|
||||
type PageFormatType = ["p", string];
|
||||
type SubDecorationType =
|
||||
| BoldFormatType
|
||||
| ItalicFormatType
|
||||
| StrikeFormatType
|
||||
| CodeFormatType
|
||||
| LinkFormatType
|
||||
| DateFormatType
|
||||
| UserFormatType
|
||||
| PageFormatType;
|
||||
type BaseDecorationType = [string];
|
||||
type AdditionalDecorationType = [string, SubDecorationType[]];
|
||||
export type DecorationType = BaseDecorationType | AdditionalDecorationType;
|
||||
|
||||
export type ColumnType =
|
||||
| "select"
|
||||
| "text"
|
||||
| "date"
|
||||
| "person"
|
||||
| "checkbox"
|
||||
| "title"
|
||||
| "multi_select"
|
||||
| "number";
|
||||
|
||||
export type ColumnSchemaType = {
|
||||
name: string;
|
||||
type: ColumnType;
|
||||
};
|
||||
|
||||
export type RowContentType =
|
||||
| string
|
||||
| boolean
|
||||
| number
|
||||
| string[]
|
||||
| { title: string; id: string };
|
||||
|
||||
export interface BaseValueType {
|
||||
id: string;
|
||||
version: number;
|
||||
created_time: number;
|
||||
last_edited_time: number;
|
||||
parent_id: string;
|
||||
parent_table: string;
|
||||
alive: boolean;
|
||||
created_by_table: string;
|
||||
created_by_id: string;
|
||||
last_edited_by_table: string;
|
||||
last_edited_by_id: string;
|
||||
content?: string[];
|
||||
}
|
||||
|
||||
export interface CollectionType {
|
||||
value: {
|
||||
id: string;
|
||||
version: number;
|
||||
name: string[][];
|
||||
schema: { [key: string]: ColumnSchemaType };
|
||||
icon: string;
|
||||
parent_id: string;
|
||||
parent_table: string;
|
||||
alive: boolean;
|
||||
copied_from: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RowType {
|
||||
value: {
|
||||
id: string;
|
||||
parent_id: string;
|
||||
properties: { [key: string]: DecorationType[] };
|
||||
};
|
||||
}
|
||||
45
src/api/utils.ts
Normal file
45
src/api/utils.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { DecorationType, ColumnType, RowContentType } from "./types";
|
||||
|
||||
export const pathToId = (path: string) =>
|
||||
`${path.substr(0, 8)}-${path.substr(8, 4)}-${path.substr(
|
||||
12,
|
||||
4
|
||||
)}-${path.substr(16, 4)}-${path.substr(20)}`;
|
||||
|
||||
export const parsePageId = (id: string) => {
|
||||
return id.includes("-") ? id : pathToId(id);
|
||||
};
|
||||
|
||||
export const getNotionValue = (
|
||||
val: DecorationType[],
|
||||
type: ColumnType
|
||||
): RowContentType => {
|
||||
switch (type) {
|
||||
case "text":
|
||||
return getTextContent(val);
|
||||
case "person":
|
||||
return (
|
||||
val.filter((v) => v.length > 1).map((v) => v[1]![0][1] as string) || []
|
||||
);
|
||||
case "checkbox":
|
||||
return val[0][0] === "Yes";
|
||||
case "date":
|
||||
if (val[0][1]![0][0] === "d") return val[0]![1]![0]![1]!.start_date;
|
||||
else return "";
|
||||
case "title":
|
||||
return getTextContent(val);
|
||||
case "select":
|
||||
return val[0][0];
|
||||
case "multi_select":
|
||||
return val[0] as string[];
|
||||
case "number":
|
||||
return Number(val[0][0]);
|
||||
default:
|
||||
console.log({ val, type });
|
||||
return "Not supported";
|
||||
}
|
||||
};
|
||||
|
||||
const getTextContent = (text: DecorationType[]) => {
|
||||
return text.reduce((prev, current) => prev + current[0], "");
|
||||
};
|
||||
43
src/index.ts
Normal file
43
src/index.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {} from "@cloudflare/workers-types";
|
||||
import { Router, Method } from "tiny-request-router";
|
||||
|
||||
import { pageRoute } from "./routes/page";
|
||||
import { tableRoute } from "./routes/table";
|
||||
import { userRoute } from "./routes/user";
|
||||
|
||||
const router = new Router();
|
||||
|
||||
router.options("*", () => new Response("", { headers: {} }));
|
||||
router.get("/v1/page/:pageId", pageRoute);
|
||||
router.get("/v1/table/:pageId", tableRoute);
|
||||
router.get("/v1/user/:userId", userRoute);
|
||||
|
||||
router.get(
|
||||
"*",
|
||||
async (event: FetchEvent) =>
|
||||
new Response(
|
||||
`Route not found!
|
||||
Available routes:
|
||||
- /v1/page/:pageId
|
||||
- /v1/table/:pageId`,
|
||||
{ status: 404 }
|
||||
)
|
||||
);
|
||||
|
||||
const handleRequest = async (fetchEvent: FetchEvent): Promise<Response> => {
|
||||
const request = fetchEvent.request;
|
||||
const { pathname } = new URL(request.url);
|
||||
|
||||
const match = router.match(request.method as Method, pathname);
|
||||
|
||||
if (!match) {
|
||||
return new Response("Endpoint not found.", { status: 404 });
|
||||
}
|
||||
|
||||
return match.handler(match.params);
|
||||
};
|
||||
|
||||
self.addEventListener("fetch", async (event: Event) => {
|
||||
const fetchEvent = event as FetchEvent;
|
||||
fetchEvent.respondWith(handleRequest(fetchEvent));
|
||||
});
|
||||
12
src/response.ts
Normal file
12
src/response.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const createResponse = (
|
||||
body: string,
|
||||
headers?: { [key: string]: string }
|
||||
) => {
|
||||
return new Response(body, {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
...headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
10
src/routes/page.ts
Normal file
10
src/routes/page.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { fetchPageById } from "../api/notion";
|
||||
import { parsePageId } from "../api/utils";
|
||||
import { createResponse } from "../response";
|
||||
|
||||
export async function pageRoute(params: { pageId: string }) {
|
||||
const pageId = parsePageId(params.pageId);
|
||||
const res = await fetchPageById(pageId);
|
||||
|
||||
return createResponse(JSON.stringify(res.recordMap.block));
|
||||
}
|
||||
53
src/routes/table.ts
Normal file
53
src/routes/table.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { fetchPageById, fetchTableData } from "../api/notion";
|
||||
import { parsePageId, getNotionValue } from "../api/utils";
|
||||
import { RowContentType, CollectionType, RowType } from "../api/types";
|
||||
import { createResponse } from "../response";
|
||||
|
||||
export async function tableRoute(params: { pageId: string }) {
|
||||
const pageId = parsePageId(params.pageId);
|
||||
const page = await fetchPageById(pageId);
|
||||
|
||||
console.log({ page });
|
||||
|
||||
const collection: CollectionType = Object.keys(page.recordMap.collection).map(
|
||||
(k) => page.recordMap.collection[k]
|
||||
)[0];
|
||||
const collectionView: {
|
||||
value: { id: CollectionType["value"]["id"] };
|
||||
} = Object.keys(page.recordMap.collection_view).map(
|
||||
(k) => page.recordMap.collection_view[k]
|
||||
)[0];
|
||||
|
||||
const table = await fetchTableData(
|
||||
collection.value.id,
|
||||
collectionView.value.id
|
||||
);
|
||||
|
||||
console.log({ table });
|
||||
|
||||
const collectionRows = collection.value.schema;
|
||||
const collectionColKeys = Object.keys(collectionRows);
|
||||
|
||||
const tableArr: RowType[] = table.result.blockIds.map(
|
||||
(id: string) => table.recordMap.block[id]
|
||||
);
|
||||
|
||||
const tableData = tableArr.filter(
|
||||
(b) =>
|
||||
b.value && b.value.properties && b.value.parent_id === collection.value.id
|
||||
);
|
||||
|
||||
const rows = tableData.map((td) => {
|
||||
let row: { [key: string]: RowContentType } = { id: td.value.id };
|
||||
collectionColKeys.forEach((key) => {
|
||||
const val = td.value.properties[key];
|
||||
if (val) {
|
||||
const schema = collectionRows[key];
|
||||
row[schema.name] = getNotionValue(val, schema.type);
|
||||
}
|
||||
});
|
||||
return row;
|
||||
});
|
||||
|
||||
return createResponse(JSON.stringify(rows));
|
||||
}
|
||||
8
src/routes/user.ts
Normal file
8
src/routes/user.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { fetchNotionUser } from "../api/notion";
|
||||
import { createResponse } from "../response";
|
||||
|
||||
export async function userRoute(params: { userId: string }) {
|
||||
const users = await fetchNotionUser([params.userId]);
|
||||
|
||||
return createResponse(JSON.stringify(users[0]));
|
||||
}
|
||||
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"module": "commonjs",
|
||||
"target": "esnext",
|
||||
"lib": ["esnext", "DOM", "DOM.Iterable", "WebWorker"],
|
||||
"alwaysStrict": true,
|
||||
"strict": true,
|
||||
"preserveConstEnums": true,
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"./src/*.ts",
|
||||
"./src/**/*.ts",
|
||||
"./node_modules/@cloudflare/workers-types/index.d.ts"
|
||||
],
|
||||
"exclude": ["node_modules/", "dist/"]
|
||||
}
|
||||
32
webpack.config.js
Normal file
32
webpack.config.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const path = require("path");
|
||||
|
||||
const mode = process.env.NODE_ENV || "production";
|
||||
|
||||
module.exports = {
|
||||
output: {
|
||||
filename: `worker.${mode}.js`,
|
||||
path: path.join(__dirname, "dist"),
|
||||
},
|
||||
target: "webworker",
|
||||
devtool: "source-map",
|
||||
mode,
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
usedExports: true,
|
||||
},
|
||||
};
|
||||
8
wrangler.example.toml
Normal file
8
wrangler.example.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
name = "notion-cloudflare-worker"
|
||||
webpack_config = "webpack.config.js"
|
||||
type = "webpack"
|
||||
|
||||
account_id = ""
|
||||
zone_id = ""
|
||||
|
||||
route = "notion-api.splitbee.io/*"
|
||||
255
yarn.lock
Normal file
255
yarn.lock
Normal file
@@ -0,0 +1,255 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@cloudflare/workers-types@^1.0.9":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workers-types/-/workers-types-1.0.9.tgz#00cfb188e93125f95ccc27d7a4c6aabd6b62e699"
|
||||
integrity sha512-x6aA5FRK0fR0pC/mkDq0nG6WNkf3aVu6vLRfA7FoMtajbvWKN9JBveI/HhbjpMOIRWfNnGd2rw6WH7NAv4XesA==
|
||||
|
||||
"@types/node@^13.13.1":
|
||||
version "13.13.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.1.tgz#1ba94c5a177a1692518bfc7b41aec0aa1a14354e"
|
||||
integrity sha512-uysqysLJ+As9jqI5yqjwP3QJrhOcUwBjHUlUxPxjbplwKoILvXVsmYWEhfmAQlrPfbRZmhJB007o4L9sKqtHqQ==
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
big.js@^5.2.2:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
||||
|
||||
braces@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
chalk@^2.3.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
||||
dependencies:
|
||||
color-name "1.1.3"
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
emojis-list@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
|
||||
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
|
||||
|
||||
enhanced-resolve@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66"
|
||||
integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
memory-fs "^0.5.0"
|
||||
tapable "^1.0.0"
|
||||
|
||||
errno@^0.1.3:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
|
||||
integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
|
||||
dependencies:
|
||||
prr "~1.0.1"
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
fill-range@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
graceful-fs@^4.1.2:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
|
||||
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||
|
||||
inherits@~2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
json5@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
|
||||
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
loader-utils@^1.0.2:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
|
||||
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
|
||||
dependencies:
|
||||
big.js "^5.2.2"
|
||||
emojis-list "^3.0.0"
|
||||
json5 "^1.0.1"
|
||||
|
||||
memory-fs@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
|
||||
integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
|
||||
dependencies:
|
||||
errno "^0.1.3"
|
||||
readable-stream "^2.0.1"
|
||||
|
||||
micromatch@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
|
||||
integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
|
||||
dependencies:
|
||||
braces "^3.0.1"
|
||||
picomatch "^2.0.5"
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
path-to-regexp@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.1.0.tgz#0b18f88b7a0ce0bfae6a25990c909ab86f512427"
|
||||
integrity sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==
|
||||
|
||||
picomatch@^2.0.5:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
|
||||
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
|
||||
|
||||
prettier@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.4.tgz#2d1bae173e355996ee355ec9830a7a1ee05457ef"
|
||||
integrity sha512-SVJIQ51spzFDvh4fIbCLvciiDMCrRhlN3mbZvv/+ycjvmF5E73bKdGfU8QDLNmjYJf+lsGnDBC4UUnvTe5OO0w==
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
prr@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
|
||||
|
||||
readable-stream@^2.0.1:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
semver@^6.0.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
tapable@^1.0.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
||||
|
||||
tiny-request-router@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/tiny-request-router/-/tiny-request-router-1.2.2.tgz#1b80694497e4e8dcbb8e93851ec7f03c6ca13e75"
|
||||
integrity sha512-6ZMFU7AP9so+hkqmMM9fJ11V44EAcYuHCmNdsyM8k94oVnNDPQwUAAPoBHqchHSpKG6yZbCasgVeRxaY5v2BCg==
|
||||
dependencies:
|
||||
path-to-regexp "^6.1.0"
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
ts-loader@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.1.tgz#ac9ae9eb8f5ebd0aa7b78b44db20691b6e31251b"
|
||||
integrity sha512-wdGs9xO8UnwASwbluehzXciBtc9HfGlYA8Aiv856etLmdv8mJfAxCkt3YpS4g7G1IsGxaCVKQ102Qh0zycpeZQ==
|
||||
dependencies:
|
||||
chalk "^2.3.0"
|
||||
enhanced-resolve "^4.0.0"
|
||||
loader-utils "^1.0.2"
|
||||
micromatch "^4.0.0"
|
||||
semver "^6.0.0"
|
||||
|
||||
typescript@^3.8.3:
|
||||
version "3.8.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
|
||||
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
Reference in New Issue
Block a user