mirror of
https://github.com/strapi/strapi.git
synced 2025-11-16 01:57:56 +00:00
Init server and http-server
This commit is contained in:
parent
76d1ac7ada
commit
bc2760f14f
@ -1,14 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Koa = require('koa');
|
|
||||||
const Router = require('koa-router');
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const { createLogger } = require('@strapi/logger');
|
const { createLogger } = require('@strapi/logger');
|
||||||
const { Database } = require('@strapi/database');
|
const { Database } = require('@strapi/database');
|
||||||
|
|
||||||
const loadConfiguration = require('./core/app-configuration');
|
const loadConfiguration = require('./core/app-configuration');
|
||||||
|
|
||||||
const { createHTTPServer } = require('./server');
|
const { createServer } = require('./server');
|
||||||
const { createContainer } = require('./container');
|
const { createContainer } = require('./container');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const initializeMiddlewares = require('./middlewares');
|
const initializeMiddlewares = require('./middlewares');
|
||||||
@ -57,9 +55,8 @@ class Strapi {
|
|||||||
|
|
||||||
this.isLoaded = false;
|
this.isLoaded = false;
|
||||||
this.reload = this.reload();
|
this.reload = this.reload();
|
||||||
this.app = new Koa();
|
this.server = createServer(strapi);
|
||||||
this.router = new Router();
|
|
||||||
this.server = createHTTPServer(this, this.app);
|
|
||||||
this.fs = createStrapiFs(this);
|
this.fs = createStrapiFs(this);
|
||||||
this.eventHub = createEventHub();
|
this.eventHub = createEventHub();
|
||||||
this.startupLogger = createStartupLogger(this);
|
this.startupLogger = createStartupLogger(this);
|
||||||
|
|||||||
64
packages/core/strapi/lib/http-server.js
Normal file
64
packages/core/strapi/lib/http-server.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
const createHTTPServer = (strapi, koaApp) => {
|
||||||
|
const connections = new Set();
|
||||||
|
|
||||||
|
// lazy creation of the request listener
|
||||||
|
let handler;
|
||||||
|
const listener = function handleRequest(req, res) {
|
||||||
|
if (!handler) {
|
||||||
|
handler = koaApp.callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler(req, res);
|
||||||
|
};
|
||||||
|
|
||||||
|
const server = http.createServer(listener);
|
||||||
|
|
||||||
|
server.on('connection', connection => {
|
||||||
|
connections.add(connection);
|
||||||
|
|
||||||
|
connection.on('close', () => {
|
||||||
|
connections.delete(connection);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// handle port in use cleanly
|
||||||
|
server.on('error', err => {
|
||||||
|
if (err.code === 'EADDRINUSE') {
|
||||||
|
return strapi.stopWithError(`The port ${err.port} is already used by another application.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
strapi.log.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.destroy = async () => {
|
||||||
|
for (const connection of connections) {
|
||||||
|
connection.destroy();
|
||||||
|
|
||||||
|
connections.delete(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server.listening) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) =>
|
||||||
|
server.close(error => {
|
||||||
|
if (error) {
|
||||||
|
return reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return server;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createHTTPServer,
|
||||||
|
};
|
||||||
@ -1,64 +1,129 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const http = require('http');
|
const Koa = require('koa');
|
||||||
|
const Router = require('@koa/router');
|
||||||
|
const mount = require('koa-mount');
|
||||||
|
|
||||||
const createHTTPServer = (strapi, koaApp) => {
|
const { createHTTPServer } = require('./http-server');
|
||||||
const connections = new Set();
|
|
||||||
|
|
||||||
// lazy creation of the request listener
|
const createRoute = (route, router) => {
|
||||||
let handler;
|
router[route.method.toLowerCase()](route.path, route.handler);
|
||||||
const listener = function handleRequest(req, res) {
|
|
||||||
if (!handler) {
|
|
||||||
handler = koaApp.callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
return handler(req, res);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const server = http.createServer(listener);
|
// TODO: connect to compose Endpoint
|
||||||
|
const addRoutes = (routes, app) => {
|
||||||
|
if (Array.isArray(routes)) {
|
||||||
|
const router = new Router();
|
||||||
|
|
||||||
server.on('connection', connection => {
|
routes.forEach(route => createRoute(route, router));
|
||||||
connections.add(connection);
|
|
||||||
|
|
||||||
connection.on('close', () => {
|
return app.use(router.routes()).use(router.allowedMethods());
|
||||||
connections.delete(connection);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// handle port in use cleanly
|
|
||||||
server.on('error', err => {
|
|
||||||
if (err.code === 'EADDRINUSE') {
|
|
||||||
return strapi.stopWithError(`The port ${err.port} is already used by another application.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strapi.log.error(err);
|
if (routes.routes) {
|
||||||
});
|
const router = new Router({ prefix: routes.prefix });
|
||||||
|
|
||||||
server.destroy = async () => {
|
routes.routes.forEach(route => createRoute(route, router));
|
||||||
for (const connection of connections) {
|
|
||||||
connection.destroy();
|
|
||||||
|
|
||||||
connections.delete(connection);
|
app.use(router.routes()).use(router.allowedMethods());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!server.listening) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) =>
|
|
||||||
server.close(error => {
|
|
||||||
if (error) {
|
|
||||||
return reject(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return server;
|
const createAPI = prefix => {
|
||||||
|
const app = new Koa();
|
||||||
|
|
||||||
|
return {
|
||||||
|
prefix,
|
||||||
|
|
||||||
|
use(fn) {
|
||||||
|
app.use(fn);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
routes(routes) {
|
||||||
|
addRoutes(routes, app);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
get middleware() {
|
||||||
|
return app;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Server
|
||||||
|
*
|
||||||
|
* @property {Koa} app
|
||||||
|
* @property {http.Server} app
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Strapi} strapi
|
||||||
|
* @returns {Server}
|
||||||
|
*/
|
||||||
|
const createServer = strapi => {
|
||||||
|
const app = new Koa();
|
||||||
|
const httpServer = createHTTPServer(strapi, this.app);
|
||||||
|
const apis = {
|
||||||
|
admin: createAPI('admin'),
|
||||||
|
'content-api': createAPI('api'),
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
app,
|
||||||
|
httpServer,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a middleware to the main koa app or an api
|
||||||
|
* @param {string|function} path
|
||||||
|
* @param {function} fn
|
||||||
|
* @returns {Server}
|
||||||
|
*/
|
||||||
|
use(path, fn) {
|
||||||
|
if (typeof path === 'function') {
|
||||||
|
app.use(path);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof path === 'string') {
|
||||||
|
apis[path].use(fn);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Use expects to be called with (fn) or (name, callback)');
|
||||||
|
},
|
||||||
|
|
||||||
|
routes(routes) {
|
||||||
|
if (routes.type) {
|
||||||
|
const api = apis[routes.type];
|
||||||
|
if (!api) {
|
||||||
|
throw new Error(`API ${routes.type} not found. Possible APIs are ${Object.keys(apis)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
apis[routes.type].routes(routes);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
addRoutes(routes, app);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
start(args) {
|
||||||
|
Object.values(apis).forEach(api => {
|
||||||
|
app.use(mount(`/${api.prefix}`, api.app));
|
||||||
|
});
|
||||||
|
|
||||||
|
return httpServer.listen(...args);
|
||||||
|
},
|
||||||
|
|
||||||
|
async destroy() {
|
||||||
|
await this.httpServer.destroy();
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createHTTPServer,
|
createServer,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,10 +14,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koa/cors": "^3.0.0",
|
"@koa/cors": "^3.0.0",
|
||||||
|
"@koa/router": "10.1.1",
|
||||||
"@strapi/admin": "3.6.8",
|
"@strapi/admin": "3.6.8",
|
||||||
"@strapi/database": "3.6.8",
|
"@strapi/database": "3.6.8",
|
||||||
"@strapi/generators": "3.6.8",
|
|
||||||
"@strapi/generate-new": "3.6.8",
|
"@strapi/generate-new": "3.6.8",
|
||||||
|
"@strapi/generators": "3.6.8",
|
||||||
"@strapi/logger": "3.6.8",
|
"@strapi/logger": "3.6.8",
|
||||||
"@strapi/plugin-content-manager": "3.6.8",
|
"@strapi/plugin-content-manager": "3.6.8",
|
||||||
"@strapi/plugin-content-type-builder": "3.6.8",
|
"@strapi/plugin-content-type-builder": "3.6.8",
|
||||||
@ -52,7 +53,7 @@
|
|||||||
"koa-i18n": "^2.1.0",
|
"koa-i18n": "^2.1.0",
|
||||||
"koa-ip": "^2.0.0",
|
"koa-ip": "^2.0.0",
|
||||||
"koa-locale": "~1.3.0",
|
"koa-locale": "~1.3.0",
|
||||||
"koa-router": "^7.4.0",
|
"koa-mount": "4.0.0",
|
||||||
"koa-session": "^6.2.0",
|
"koa-session": "^6.2.0",
|
||||||
"koa-static": "^5.0.0",
|
"koa-static": "^5.0.0",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
|
|||||||
47
yarn.lock
47
yarn.lock
@ -1932,6 +1932,17 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
vary "^1.1.2"
|
vary "^1.1.2"
|
||||||
|
|
||||||
|
"@koa/router@10.1.1":
|
||||||
|
version "10.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@koa/router/-/router-10.1.1.tgz#8e5a85c9b243e0bc776802c0de564561e57a5f78"
|
||||||
|
integrity sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.1.1"
|
||||||
|
http-errors "^1.7.3"
|
||||||
|
koa-compose "^4.1.0"
|
||||||
|
methods "^1.1.2"
|
||||||
|
path-to-regexp "^6.1.0"
|
||||||
|
|
||||||
"@lerna/add@3.21.0":
|
"@lerna/add@3.21.0":
|
||||||
version "3.21.0"
|
version "3.21.0"
|
||||||
resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.21.0.tgz#27007bde71cc7b0a2969ab3c2f0ae41578b4577b"
|
resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.21.0.tgz#27007bde71cc7b0a2969ab3c2f0ae41578b4577b"
|
||||||
@ -10778,7 +10789,7 @@ http-errors@1.7.3, http-errors@~1.7.2:
|
|||||||
statuses ">= 1.5.0 < 2"
|
statuses ">= 1.5.0 < 2"
|
||||||
toidentifier "1.0.0"
|
toidentifier "1.0.0"
|
||||||
|
|
||||||
http-errors@^1.3.1, http-errors@^1.6.3, http-errors@^1.7.3:
|
http-errors@^1.6.3, http-errors@^1.7.3:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
|
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
|
||||||
integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
|
integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
|
||||||
@ -12895,6 +12906,14 @@ koa-locale@~1.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delegates "1.0.0"
|
delegates "1.0.0"
|
||||||
|
|
||||||
|
koa-mount@4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-4.0.0.tgz#e0265e58198e1a14ef889514c607254ff386329c"
|
||||||
|
integrity sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.0.1"
|
||||||
|
koa-compose "^4.1.0"
|
||||||
|
|
||||||
koa-passport@4.1.4:
|
koa-passport@4.1.4:
|
||||||
version "4.1.4"
|
version "4.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa"
|
resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa"
|
||||||
@ -12909,18 +12928,6 @@ koa-range@0.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
stream-slice "^0.1.2"
|
stream-slice "^0.1.2"
|
||||||
|
|
||||||
koa-router@^7.4.0:
|
|
||||||
version "7.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.4.0.tgz#aee1f7adc02d5cb31d7d67465c9eacc825e8c5e0"
|
|
||||||
integrity sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g==
|
|
||||||
dependencies:
|
|
||||||
debug "^3.1.0"
|
|
||||||
http-errors "^1.3.1"
|
|
||||||
koa-compose "^3.0.0"
|
|
||||||
methods "^1.0.1"
|
|
||||||
path-to-regexp "^1.1.1"
|
|
||||||
urijs "^1.19.0"
|
|
||||||
|
|
||||||
koa-send@^5.0.0:
|
koa-send@^5.0.0:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
|
resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
|
||||||
@ -14065,7 +14072,7 @@ merge2@^1.2.3, merge2@^1.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||||
|
|
||||||
methods@1.1.2, methods@^1.0.1, methods@^1.1.2, methods@~1.1.2:
|
methods@1.1.2, methods@^1.1.2, methods@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||||
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
||||||
@ -15893,7 +15900,7 @@ path-to-regexp@0.1.7:
|
|||||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||||
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||||
|
|
||||||
path-to-regexp@^1.1.1, path-to-regexp@^1.7.0:
|
path-to-regexp@^1.7.0:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
|
||||||
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
|
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
|
||||||
@ -15905,6 +15912,11 @@ path-to-regexp@^3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f"
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f"
|
||||||
integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==
|
integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==
|
||||||
|
|
||||||
|
path-to-regexp@^6.1.0:
|
||||||
|
version "6.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38"
|
||||||
|
integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==
|
||||||
|
|
||||||
path-type@^1.0.0:
|
path-type@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||||
@ -20976,11 +20988,6 @@ uri-js@^4.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
urijs@^1.19.0:
|
|
||||||
version "1.19.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.7.tgz#4f594e59113928fea63c00ce688fb395b1168ab9"
|
|
||||||
integrity sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==
|
|
||||||
|
|
||||||
urix@^0.1.0:
|
urix@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user