@dr.pogodin/react-utils 1.21.3 → 1.21.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/build/development/server/server.js +1 -1
- package/build/development/server/server.js.map +1 -1
- package/build/development/shared/utils/index.js.map +1 -1
- package/build/development/shared/utils/time.js +48 -0
- package/build/development/shared/utils/time.js.map +1 -1
- package/build/development/style.css +2 -2
- package/build/development/web.bundle.js +11 -1
- package/build/production/server/server.js +1 -1
- package/build/production/server/server.js.map +1 -1
- package/build/production/shared/utils/index.js.map +1 -1
- package/build/production/shared/utils/time.js +23 -2
- package/build/production/shared/utils/time.js.map +1 -1
- package/build/production/web.bundle.js +1 -1
- package/build/production/web.bundle.js.LICENSE.txt +7 -0
- package/build/production/web.bundle.js.map +1 -1
- package/package.json +34 -38
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ var _url = require("url");
|
|
|
11
11
|
var _lodash = require("lodash");
|
|
12
12
|
var _compression = _interopRequireDefault(require("compression"));
|
|
13
13
|
var _cookieParser = _interopRequireDefault(require("cookie-parser"));
|
|
14
|
-
var _csurf = _interopRequireDefault(require("csurf"));
|
|
14
|
+
var _csurf = _interopRequireDefault(require("@dr.pogodin/csurf"));
|
|
15
15
|
var _express = _interopRequireDefault(require("express"));
|
|
16
16
|
var _serveFavicon = _interopRequireDefault(require("serve-favicon"));
|
|
17
17
|
var _helmet = _interopRequireDefault(require("helmet"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["defaultCspSettings","directives","mapValues","helmet","contentSecurityPolicy","getDefaultDirectives","array","filter","item","push","getDefaultCspSettings","cloneDeep","factory","webpackConfig","options","rendererOps","pick","renderer","rendererFactory","publicPath","output","server","express","beforeExpressJsSetup","logger","httpsRedirect","use","req","res","next","schema","headers","url","host","originalUrl","redirect","compression","crossOriginEmbedderPolicy","crossOriginOpenerPolicy","crossOriginResourcePolicy","noCsp","nonce","uuid","cspNonce","cspSettings","cspSettingsHook","favicon","send","json","limit","urlencoded","extended","cookieParser","requestIp","mw","csrf","cookie","loggerMiddleware","token","clientIp","FORMAT","stream","write","info","bind","get","static","path","setHeaders","set","devMode","global","location","href","pathToFileURL","process","cwd","sep","webpack","require","webpackDevMiddleware","webpackHotMiddleware","compiler","serverSideRender","onExpressJsSetup","newError","ERRORS","NOT_FOUND","CODES","dontAttachDefaultErrorHandler","beforeExpressJsError","error","headersSent","status","INTERNAL_SERVER_ERROR","serverSide","log","message","getErrorForCode","env","NODE_ENV","undefined"],"sources":["../../../src/server/server.js"],"sourcesContent":["/**\n * Creation of standard ExpressJS server for ReactJS apps.\n */\n\nimport { sep } from 'path';\nimport { pathToFileURL } from 'url';\n\nimport {\n cloneDeep,\n mapValues,\n pick,\n} from 'lodash';\n\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport csrf from 'csurf';\nimport express from 'express';\nimport favicon from 'serve-favicon';\nimport helmet from 'helmet';\nimport loggerMiddleware from 'morgan';\nimport requestIp from 'request-ip';\nimport { v4 as uuid } from 'uuid';\n\nimport rendererFactory from './renderer';\n\nimport {\n CODES,\n ERRORS,\n getErrorForCode,\n newError,\n} from './utils/errors';\n\n/**\n * Default Content Security Policy settings.\n * @ignore\n */\nconst defaultCspSettings = {\n directives: mapValues(\n helmet.contentSecurityPolicy.getDefaultDirectives(),\n\n // 'https:' options (automatic re-write of insecure URLs to secure ones)\n // is removed to facilitate local development with HTTP server. In cloud\n // deployments we assume Apache or Nginx server in front of out app takes\n // care about such re-writes.\n (array) => array.filter((item) => item !== 'https:'),\n ),\n};\ndefaultCspSettings.directives['frame-src'] = [\n \"'self'\",\n\n // YouTube domain is whitelisted to allow <YouTubeVideo> component to work\n // out of box.\n 'https://*.youtube.com',\n];\ndefaultCspSettings.directives['script-src'].push(\"'unsafe-eval'\");\n\n// No need for automatic re-writes via Content Security Policy settings:\n// the forefront Apache or Nginx server is supposed to take care of this\n// in production cloud deployments.\ndelete defaultCspSettings.directives['upgrade-insecure-requests'];\n\n/**\n * @category Utilities\n * @func server/getDefaultCspSettings\n * @global\n * @desc\n * ```js\n * import { server } from '@dr.pogodin/react-utils';\n * const { getDefaultCspSettings } from '@dr.pogodin/react-utils';\n * ```\n * @return {{\n * directives: object\n * }} A deep copy of default CSP settings object used by `react-utils`,\n * with the exception of `nonce-xxx` clause in `script-src` directive,\n * which is added dynamically for each request.\n */\nexport function getDefaultCspSettings() {\n return cloneDeep(defaultCspSettings);\n}\n\nexport default async function factory(webpackConfig, options) {\n const rendererOps = pick(options, [\n 'Application',\n 'beforeRender',\n 'favicon',\n 'logger',\n 'maxSsrRounds',\n 'noCsp',\n 'ssrTimeout',\n 'staticCacheController',\n 'staticCacheSize',\n ]);\n const renderer = rendererFactory(webpackConfig, rendererOps);\n const { publicPath } = webpackConfig.output;\n\n const server = express();\n\n if (options.beforeExpressJsSetup) {\n await options.beforeExpressJsSetup(server);\n }\n\n server.logger = options.logger;\n\n if (options.httpsRedirect) {\n server.use((req, res, next) => {\n const schema = req.headers['x-forwarded-proto'];\n if (schema === 'http') {\n let url = `https://${req.headers.host}`;\n if (req.originalUrl !== '/') url += req.originalUrl;\n return res.redirect(url);\n }\n return next();\n });\n }\n\n server.use(compression());\n server.use(\n helmet({\n contentSecurityPolicy: false,\n crossOriginEmbedderPolicy: false,\n crossOriginOpenerPolicy: false,\n crossOriginResourcePolicy: false,\n }),\n );\n\n if (!options.noCsp) {\n server.use((req, res, next) => {\n req.nonce = uuid();\n\n // TODO: This is deprecated, but it is kept for now for backward\n // compatibility. Should be removed sometime later.\n req.cspNonce = req.nonce;\n\n // The deep clone is necessary here to ensure that default value can't be\n // mutated during request processing.\n let cspSettings = cloneDeep(defaultCspSettings);\n cspSettings.directives['script-src'].push(`'nonce-${req.nonce}'`);\n if (options.cspSettingsHook) {\n cspSettings = options.cspSettingsHook(cspSettings, req);\n }\n helmet.contentSecurityPolicy(cspSettings)(req, res, next);\n });\n }\n\n if (options.favicon) {\n server.use(favicon(options.favicon));\n }\n\n server.use('/robots.txt', (req, res) => res.send('User-agent: *\\nDisallow:'));\n\n server.use(express.json({ limit: '300kb' }));\n server.use(express.urlencoded({ extended: false }));\n server.use(cookieParser());\n server.use(requestIp.mw());\n\n server.use(csrf({ cookie: true }));\n\n loggerMiddleware.token('ip', (req) => req.clientIp);\n const FORMAT = ':ip > :status :method :url :response-time ms :res[content-length] :referrer :user-agent';\n server.use(loggerMiddleware(FORMAT, {\n stream: {\n write: options.logger.info.bind(options.logger),\n },\n }));\n\n // Note: no matter the \"public path\", we want the service worker, if any,\n // to be served from the root, to have all web app pages in its scope.\n // Thus, this setup to serve it. Probably, need some more configuration\n // for special cases, but this will do for now.\n server.get('/__service-worker.js', express.static(\n webpackConfig.output.path,\n {\n setHeaders: (res) => res.set('Cache-Control', 'no-cache'),\n },\n ));\n\n /* Setup of Hot Module Reloading for development environment.\n * These dependencies are not used, nor installed for production use,\n * hence we should violate some import-related lint rules. */\n /* eslint-disable global-require */\n /* eslint-disable import/no-extraneous-dependencies */\n /* eslint-disable import/no-unresolved */\n if (options.devMode) {\n // This is a workaround for SASS bug:\n // https://github.com/dart-lang/sdk/issues/27979\n // which manifests itself sometimes when webpack dev middleware is used\n // (in dev mode), and app modules are imported in some unfortunate ways.\n if (!global.location) {\n global.location = {\n href: `${pathToFileURL(process.cwd()).href}${sep}`,\n };\n }\n\n const webpack = require('webpack');\n const webpackDevMiddleware = require('webpack-dev-middleware');\n const webpackHotMiddleware = require('webpack-hot-middleware');\n const compiler = webpack(webpackConfig);\n server.use(webpackDevMiddleware(compiler, {\n publicPath,\n serverSideRender: true,\n }));\n server.use(webpackHotMiddleware(compiler));\n }\n /* eslint-enable global-require */\n /* eslint-enable import/no-extraneous-dependencies */\n /* eslint-enable import/no-unresolved */\n\n server.use(publicPath, express.static(webpackConfig.output.path));\n\n if (options.onExpressJsSetup) {\n await options.onExpressJsSetup(server);\n }\n server.use(renderer);\n\n /* Detects 404 errors, and forwards them to the error handler. */\n server.use((req, res, next) => {\n next(newError(ERRORS.NOT_FOUND, CODES.NOT_FOUND));\n });\n\n let dontAttachDefaultErrorHandler;\n if (options.beforeExpressJsError) {\n dontAttachDefaultErrorHandler = await options.beforeExpressJsError(server);\n }\n\n /* Error handler. */\n if (!dontAttachDefaultErrorHandler) {\n // TODO: Do we need this error handler at all? It actually seems to do\n // what the default ExpressJS error handler does anyway, see:\n // https://expressjs.com/en/guide/error-handling.html\n //\n // TODO: It is better to move the default error handler definition\n // to a stand-alone function at top-level, but the use of options.logger\n // prevents to do it without some extra refactoring. Should be done sometime\n // though.\n server.use((error, req, res, next) => {\n // TODO: This is needed to correctly handled any errors thrown after\n // sending initial response to the client.\n if (res.headersSent) return next(error);\n\n const status = error.status || CODES.INTERNAL_SERVER_ERROR;\n const serverSide = status >= CODES.INTERNAL_SERVER_ERROR;\n\n // Log server-side errors always, client-side at debug level only.\n options.logger.log(serverSide ? 'error' : 'debug', error);\n\n let message = error.message || getErrorForCode(status);\n if (serverSide && process.env.NODE_ENV === 'production') {\n message = ERRORS.INTERNAL_SERVER_ERROR;\n }\n\n res.status(status).send(message);\n return undefined;\n });\n }\n\n return server;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":["defaultCspSettings","directives","mapValues","helmet","contentSecurityPolicy","getDefaultDirectives","array","filter","item","push","getDefaultCspSettings","cloneDeep","factory","webpackConfig","options","rendererOps","pick","renderer","rendererFactory","publicPath","output","server","express","beforeExpressJsSetup","logger","httpsRedirect","use","req","res","next","schema","headers","url","host","originalUrl","redirect","compression","crossOriginEmbedderPolicy","crossOriginOpenerPolicy","crossOriginResourcePolicy","noCsp","nonce","uuid","cspNonce","cspSettings","cspSettingsHook","favicon","send","json","limit","urlencoded","extended","cookieParser","requestIp","mw","csrf","cookie","loggerMiddleware","token","clientIp","FORMAT","stream","write","info","bind","get","static","path","setHeaders","set","devMode","global","location","href","pathToFileURL","process","cwd","sep","webpack","require","webpackDevMiddleware","webpackHotMiddleware","compiler","serverSideRender","onExpressJsSetup","newError","ERRORS","NOT_FOUND","CODES","dontAttachDefaultErrorHandler","beforeExpressJsError","error","headersSent","status","INTERNAL_SERVER_ERROR","serverSide","log","message","getErrorForCode","env","NODE_ENV","undefined"],"sources":["../../../src/server/server.js"],"sourcesContent":["/**\n * Creation of standard ExpressJS server for ReactJS apps.\n */\n\nimport { sep } from 'path';\nimport { pathToFileURL } from 'url';\n\nimport {\n cloneDeep,\n mapValues,\n pick,\n} from 'lodash';\n\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport csrf from '@dr.pogodin/csurf';\nimport express from 'express';\nimport favicon from 'serve-favicon';\nimport helmet from 'helmet';\nimport loggerMiddleware from 'morgan';\nimport requestIp from 'request-ip';\nimport { v4 as uuid } from 'uuid';\n\nimport rendererFactory from './renderer';\n\nimport {\n CODES,\n ERRORS,\n getErrorForCode,\n newError,\n} from './utils/errors';\n\n/**\n * Default Content Security Policy settings.\n * @ignore\n */\nconst defaultCspSettings = {\n directives: mapValues(\n helmet.contentSecurityPolicy.getDefaultDirectives(),\n\n // 'https:' options (automatic re-write of insecure URLs to secure ones)\n // is removed to facilitate local development with HTTP server. In cloud\n // deployments we assume Apache or Nginx server in front of out app takes\n // care about such re-writes.\n (array) => array.filter((item) => item !== 'https:'),\n ),\n};\ndefaultCspSettings.directives['frame-src'] = [\n \"'self'\",\n\n // YouTube domain is whitelisted to allow <YouTubeVideo> component to work\n // out of box.\n 'https://*.youtube.com',\n];\ndefaultCspSettings.directives['script-src'].push(\"'unsafe-eval'\");\n\n// No need for automatic re-writes via Content Security Policy settings:\n// the forefront Apache or Nginx server is supposed to take care of this\n// in production cloud deployments.\ndelete defaultCspSettings.directives['upgrade-insecure-requests'];\n\n/**\n * @category Utilities\n * @func server/getDefaultCspSettings\n * @global\n * @desc\n * ```js\n * import { server } from '@dr.pogodin/react-utils';\n * const { getDefaultCspSettings } from '@dr.pogodin/react-utils';\n * ```\n * @return {{\n * directives: object\n * }} A deep copy of default CSP settings object used by `react-utils`,\n * with the exception of `nonce-xxx` clause in `script-src` directive,\n * which is added dynamically for each request.\n */\nexport function getDefaultCspSettings() {\n return cloneDeep(defaultCspSettings);\n}\n\nexport default async function factory(webpackConfig, options) {\n const rendererOps = pick(options, [\n 'Application',\n 'beforeRender',\n 'favicon',\n 'logger',\n 'maxSsrRounds',\n 'noCsp',\n 'ssrTimeout',\n 'staticCacheController',\n 'staticCacheSize',\n ]);\n const renderer = rendererFactory(webpackConfig, rendererOps);\n const { publicPath } = webpackConfig.output;\n\n const server = express();\n\n if (options.beforeExpressJsSetup) {\n await options.beforeExpressJsSetup(server);\n }\n\n server.logger = options.logger;\n\n if (options.httpsRedirect) {\n server.use((req, res, next) => {\n const schema = req.headers['x-forwarded-proto'];\n if (schema === 'http') {\n let url = `https://${req.headers.host}`;\n if (req.originalUrl !== '/') url += req.originalUrl;\n return res.redirect(url);\n }\n return next();\n });\n }\n\n server.use(compression());\n server.use(\n helmet({\n contentSecurityPolicy: false,\n crossOriginEmbedderPolicy: false,\n crossOriginOpenerPolicy: false,\n crossOriginResourcePolicy: false,\n }),\n );\n\n if (!options.noCsp) {\n server.use((req, res, next) => {\n req.nonce = uuid();\n\n // TODO: This is deprecated, but it is kept for now for backward\n // compatibility. Should be removed sometime later.\n req.cspNonce = req.nonce;\n\n // The deep clone is necessary here to ensure that default value can't be\n // mutated during request processing.\n let cspSettings = cloneDeep(defaultCspSettings);\n cspSettings.directives['script-src'].push(`'nonce-${req.nonce}'`);\n if (options.cspSettingsHook) {\n cspSettings = options.cspSettingsHook(cspSettings, req);\n }\n helmet.contentSecurityPolicy(cspSettings)(req, res, next);\n });\n }\n\n if (options.favicon) {\n server.use(favicon(options.favicon));\n }\n\n server.use('/robots.txt', (req, res) => res.send('User-agent: *\\nDisallow:'));\n\n server.use(express.json({ limit: '300kb' }));\n server.use(express.urlencoded({ extended: false }));\n server.use(cookieParser());\n server.use(requestIp.mw());\n\n server.use(csrf({ cookie: true }));\n\n loggerMiddleware.token('ip', (req) => req.clientIp);\n const FORMAT = ':ip > :status :method :url :response-time ms :res[content-length] :referrer :user-agent';\n server.use(loggerMiddleware(FORMAT, {\n stream: {\n write: options.logger.info.bind(options.logger),\n },\n }));\n\n // Note: no matter the \"public path\", we want the service worker, if any,\n // to be served from the root, to have all web app pages in its scope.\n // Thus, this setup to serve it. Probably, need some more configuration\n // for special cases, but this will do for now.\n server.get('/__service-worker.js', express.static(\n webpackConfig.output.path,\n {\n setHeaders: (res) => res.set('Cache-Control', 'no-cache'),\n },\n ));\n\n /* Setup of Hot Module Reloading for development environment.\n * These dependencies are not used, nor installed for production use,\n * hence we should violate some import-related lint rules. */\n /* eslint-disable global-require */\n /* eslint-disable import/no-extraneous-dependencies */\n /* eslint-disable import/no-unresolved */\n if (options.devMode) {\n // This is a workaround for SASS bug:\n // https://github.com/dart-lang/sdk/issues/27979\n // which manifests itself sometimes when webpack dev middleware is used\n // (in dev mode), and app modules are imported in some unfortunate ways.\n if (!global.location) {\n global.location = {\n href: `${pathToFileURL(process.cwd()).href}${sep}`,\n };\n }\n\n const webpack = require('webpack');\n const webpackDevMiddleware = require('webpack-dev-middleware');\n const webpackHotMiddleware = require('webpack-hot-middleware');\n const compiler = webpack(webpackConfig);\n server.use(webpackDevMiddleware(compiler, {\n publicPath,\n serverSideRender: true,\n }));\n server.use(webpackHotMiddleware(compiler));\n }\n /* eslint-enable global-require */\n /* eslint-enable import/no-extraneous-dependencies */\n /* eslint-enable import/no-unresolved */\n\n server.use(publicPath, express.static(webpackConfig.output.path));\n\n if (options.onExpressJsSetup) {\n await options.onExpressJsSetup(server);\n }\n server.use(renderer);\n\n /* Detects 404 errors, and forwards them to the error handler. */\n server.use((req, res, next) => {\n next(newError(ERRORS.NOT_FOUND, CODES.NOT_FOUND));\n });\n\n let dontAttachDefaultErrorHandler;\n if (options.beforeExpressJsError) {\n dontAttachDefaultErrorHandler = await options.beforeExpressJsError(server);\n }\n\n /* Error handler. */\n if (!dontAttachDefaultErrorHandler) {\n // TODO: Do we need this error handler at all? It actually seems to do\n // what the default ExpressJS error handler does anyway, see:\n // https://expressjs.com/en/guide/error-handling.html\n //\n // TODO: It is better to move the default error handler definition\n // to a stand-alone function at top-level, but the use of options.logger\n // prevents to do it without some extra refactoring. Should be done sometime\n // though.\n server.use((error, req, res, next) => {\n // TODO: This is needed to correctly handled any errors thrown after\n // sending initial response to the client.\n if (res.headersSent) return next(error);\n\n const status = error.status || CODES.INTERNAL_SERVER_ERROR;\n const serverSide = status >= CODES.INTERNAL_SERVER_ERROR;\n\n // Log server-side errors always, client-side at debug level only.\n options.logger.log(serverSide ? 'error' : 'debug', error);\n\n let message = error.message || getErrorForCode(status);\n if (serverSide && process.env.NODE_ENV === 'production') {\n message = ERRORS.INTERNAL_SERVER_ERROR;\n }\n\n res.status(status).send(message);\n return undefined;\n });\n }\n\n return server;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["themed","COMPOSE","PRIORITY","NODE_CONFIG_ENV","process","env","NODE_ENV","JU","webpack","requireWeak","__dirname","withRetries","action","maxRetries","interval","n","error","timer"],"sources":["../../../../src/shared/utils/index.js"],"sourcesContent":["import themed, {\n COMPOSE,\n PRIORITY,\n ThemeProvider,\n} from '@dr.pogodin/react-themes';\n\nimport config from './config';\nimport * as isomorphy from './isomorphy';\nimport time, { timer } from './time';\nimport * as webpack from './webpack';\n\nexport * from './Barrier';\nexport { default as Emitter } from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport { default as splitComponent } from './splitComponent';\n\nthemed.COMPOSE = COMPOSE;\nthemed.PRIORITY = PRIORITY;\n\n// Note: it should be done this way, as in some environments\n// \"process\" might not exist, and process.env.NODE_CONFIG_ENV\n// not injected by Webpack.\nlet NODE_CONFIG_ENV;\ntry {\n NODE_CONFIG_ENV = process.env.NODE_CONFIG_ENV;\n} catch { /* noop */ }\n\nconst env = NODE_CONFIG_ENV || process.env.NODE_ENV;\nconst JU = env !== 'production' && webpack.requireWeak('./jest', __dirname);\n\n/**\n * @category Utilities\n * @global\n * @func withRetries\n * @desc\n * ```js\n * import { withRetries } from '@dr.pogodin/react-utils';\n * ```\n * Attempts to perform given asynchronous `action` up to `maxRetries` times,\n * with the given `interval` between attempts. If any attempt is successful,\n * the result is returned immediately, with no further attempts done;\n * otherwise, if all attempts fail, the result Promise rejects after the last\n * attempt.\n * @param {function} action\n * @param {number} [maxRetries=5] Optional. Maximum number of retries. Defaults\n * to 5 attempts.\n * @param {number} [interval=1000] Optional. Interval between retries [ms].\n * Defaults to 1 second.\n * @return {Promise} Resolves to the result of successful operation, or\n * rejects with the error from the latst failed attempt.\n * @example\n * import { withRetries } from '@dr.pogodin/react-utils';\n *\n * let firstCall = true;\n *\n * function sampleAction() {\n * if (!firstCall) return 'success';\n * firstCall = false;\n * throw Error('The first call to this method fails');\n * }\n *\n * withRetries(sampleAction).then(console.log);\n * // It will print 'success' after one second, once the second attempt\n * // is performed.\n */\nexport async function withRetries(action, maxRetries = 5, interval = 1000) {\n /* eslint-disable no-await-in-loop */\n for (let n = 1; ; ++n) {\n try {\n return await action();\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n /* eslint-enable no-await-in-loop */\n}\n\nexport {\n config,\n isomorphy,\n JU,\n themed,\n ThemeProvider,\n time,\n webpack,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAMA;AACA;AAAyC;AACzC;AACA;AAAqC;AAErC;AAAA;EAAA;EAAA;EAAA;EAAA;IAAA;IAAA;MAAA;IAAA;EAAA;AAAA;AACA;AACA;AACA;AAA6D;AAAA;AAE7DA,oBAAM,CAACC,OAAO,GAAGA,oBAAO;AACxBD,oBAAM,CAACE,QAAQ,GAAGA,qBAAQ;;AAE1B;AACA;AACA;AACA,IAAIC,eAAe;AACnB,IAAI;EACFA,eAAe,GAAGC,OAAO,CAACC,GAAG,CAACF,eAAe;AAC/C,CAAC,CAAC,MAAM,CAAE
|
|
1
|
+
{"version":3,"file":"index.js","names":["themed","COMPOSE","PRIORITY","NODE_CONFIG_ENV","process","env","NODE_ENV","JU","webpack","requireWeak","__dirname","withRetries","action","maxRetries","interval","n","error","timer"],"sources":["../../../../src/shared/utils/index.js"],"sourcesContent":["import themed, {\n COMPOSE,\n PRIORITY,\n ThemeProvider,\n} from '@dr.pogodin/react-themes';\n\nimport config from './config';\nimport * as isomorphy from './isomorphy';\nimport time, { timer } from './time';\nimport * as webpack from './webpack';\n\nexport * from './Barrier';\nexport { default as Emitter } from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport { default as splitComponent } from './splitComponent';\n\nthemed.COMPOSE = COMPOSE;\nthemed.PRIORITY = PRIORITY;\n\n// Note: it should be done this way, as in some environments\n// \"process\" might not exist, and process.env.NODE_CONFIG_ENV\n// not injected by Webpack.\nlet NODE_CONFIG_ENV;\ntry {\n NODE_CONFIG_ENV = process.env.NODE_CONFIG_ENV;\n} catch { /* noop */ }\n\nconst env = NODE_CONFIG_ENV || process.env.NODE_ENV;\nconst JU = env !== 'production' && webpack.requireWeak('./jest', __dirname);\n\n/**\n * @category Utilities\n * @global\n * @func withRetries\n * @desc\n * ```js\n * import { withRetries } from '@dr.pogodin/react-utils';\n * ```\n * Attempts to perform given asynchronous `action` up to `maxRetries` times,\n * with the given `interval` between attempts. If any attempt is successful,\n * the result is returned immediately, with no further attempts done;\n * otherwise, if all attempts fail, the result Promise rejects after the last\n * attempt.\n * @param {function} action\n * @param {number} [maxRetries=5] Optional. Maximum number of retries. Defaults\n * to 5 attempts.\n * @param {number} [interval=1000] Optional. Interval between retries [ms].\n * Defaults to 1 second.\n * @return {Promise} Resolves to the result of successful operation, or\n * rejects with the error from the latst failed attempt.\n * @example\n * import { withRetries } from '@dr.pogodin/react-utils';\n *\n * let firstCall = true;\n *\n * function sampleAction() {\n * if (!firstCall) return 'success';\n * firstCall = false;\n * throw Error('The first call to this method fails');\n * }\n *\n * withRetries(sampleAction).then(console.log);\n * // It will print 'success' after one second, once the second attempt\n * // is performed.\n */\nexport async function withRetries(action, maxRetries = 5, interval = 1000) {\n /* eslint-disable no-await-in-loop */\n for (let n = 1; ; ++n) {\n try {\n return await action();\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n /* eslint-enable no-await-in-loop */\n}\n\nexport {\n config,\n isomorphy,\n JU,\n themed,\n ThemeProvider,\n time,\n webpack,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAMA;AACA;AAAyC;AACzC;AACA;AAAqC;AAErC;AAAA;EAAA;EAAA;EAAA;EAAA;IAAA;IAAA;MAAA;IAAA;EAAA;AAAA;AACA;AACA;AACA;AAA6D;AAAA;AAE7DA,oBAAM,CAACC,OAAO,GAAGA,oBAAO;AACxBD,oBAAM,CAACE,QAAQ,GAAGA,qBAAQ;;AAE1B;AACA;AACA;AACA,IAAIC,eAAe;AACnB,IAAI;EACFA,eAAe,GAAGC,OAAO,CAACC,GAAG,CAACF,eAAe;AAC/C,CAAC,CAAC,MAAM,CAAE;AAEV,MAAME,GAAG,GAAGF,eAAe,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ;AACnD,MAAMC,EAAE,GAAGF,GAAG,KAAK,YAAY,IAAIG,OAAO,CAACC,WAAW,WAAWC,SAAS,CAAC;;AAE3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAlCA;AAmCO,eAAeC,WAAW,CAACC,MAAM,EAAEC,UAAU,GAAG,CAAC,EAAEC,QAAQ,GAAG,IAAI,EAAE;EACzE;EACA,KAAK,IAAIC,CAAC,GAAG,CAAC,GAAI,EAAEA,CAAC,EAAE;IACrB,IAAI;MACF,OAAO,MAAMH,MAAM,EAAE;IACvB,CAAC,CAAC,OAAOI,KAAK,EAAE;MACd,IAAID,CAAC,GAAGF,UAAU,EAAE,MAAM,IAAAI,WAAK,EAACH,QAAQ,CAAC,CAAC,KACrC,MAAME,KAAK;IAClB;EACF;EACA;AACF"}
|
|
@@ -7,11 +7,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.default = void 0;
|
|
8
8
|
exports.timer = timer;
|
|
9
9
|
exports.useCurrent = useCurrent;
|
|
10
|
+
exports.useTimezoneOffset = useTimezoneOffset;
|
|
11
|
+
var _cookie = _interopRequireDefault(require("cookie"));
|
|
10
12
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
11
13
|
var _lodash = require("lodash");
|
|
12
14
|
var _react = require("react");
|
|
13
15
|
var _reactGlobalState = require("@dr.pogodin/react-global-state");
|
|
14
16
|
var _Barrier = require("./Barrier");
|
|
17
|
+
/* global document */
|
|
18
|
+
|
|
15
19
|
/**
|
|
16
20
|
* @static
|
|
17
21
|
* @const SEC_MS
|
|
@@ -135,8 +139,52 @@ function useCurrent({
|
|
|
135
139
|
}, [autorefresh, precision, setter]);
|
|
136
140
|
return now;
|
|
137
141
|
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Returns client's timezone offset (the difference, in milliseconds, between
|
|
145
|
+
* a timestamp evaluated in the user's timezone, and the same moment of time
|
|
146
|
+
* represented as a standard timestamp in UTC timzone) in an SSR-friendly way,
|
|
147
|
+
* i.e. adding the result of this hook to a standard timestamp will shift it
|
|
148
|
+
* in such way that when formatted to a human-readable form it will represent
|
|
149
|
+
* the time in the user's timezone.
|
|
150
|
+
*
|
|
151
|
+
* Technically, on the first ever call at the server-side it returns zero,
|
|
152
|
+
* then at the client side it initially returns zero, then determines the actual
|
|
153
|
+
* timezone offset, returns it from the hook and also sets it as a cookie.
|
|
154
|
+
* Subsequent renders on the server side will use that cookie to report
|
|
155
|
+
* the user's timezone right away.
|
|
156
|
+
*
|
|
157
|
+
* @param {object} [options] Optional settings.
|
|
158
|
+
* @param {string} [options.cookieName="timezoneOffset"] Optional. The name of
|
|
159
|
+
* cookie to use to store the timezone offset. Defaults "timezoneOffset". Set
|
|
160
|
+
* to a falsy value to forbid using cookies altogether (in that case the hook
|
|
161
|
+
* will always return zero value at the server-side, and in the first render
|
|
162
|
+
* at the client-side).
|
|
163
|
+
* @return {number} Timezone offset.
|
|
164
|
+
*/
|
|
165
|
+
function useTimezoneOffset({
|
|
166
|
+
cookieName = 'timezoneOffset'
|
|
167
|
+
} = {}) {
|
|
168
|
+
const ssrContext = (0, _reactGlobalState.getSsrContext)(false);
|
|
169
|
+
const [offset, setOffset] = (0, _react.useState)(() => {
|
|
170
|
+
const value = cookieName && ssrContext?.req?.cookies?.[cookieName];
|
|
171
|
+
return value ? parseInt(value, 10) : 0;
|
|
172
|
+
});
|
|
173
|
+
(0, _react.useEffect)(() => {
|
|
174
|
+
const date = new Date();
|
|
175
|
+
const value = -date.getTimezoneOffset() * _dayjs.default.MIN_MS;
|
|
176
|
+
setOffset(value);
|
|
177
|
+
if (cookieName) {
|
|
178
|
+
document.cookie = _cookie.default.serialize(cookieName, value, {
|
|
179
|
+
path: '/'
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}, [cookieName]);
|
|
183
|
+
return offset;
|
|
184
|
+
}
|
|
138
185
|
_dayjs.default.timer = timer;
|
|
139
186
|
_dayjs.default.useCurrent = useCurrent;
|
|
187
|
+
_dayjs.default.useTimezoneOffset = useTimezoneOffset;
|
|
140
188
|
var _default = _dayjs.default;
|
|
141
189
|
exports.default = _default;
|
|
142
190
|
//# sourceMappingURL=time.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","names":["dayjs","SEC_MS","MIN_MS","HOUR_MS","DAY_MS","YEAR_MS","now","Date","timer","timeout","res","Barrier","id","setTimeout","resolve","bind","abort","clearTimeout","noop","useCurrent","autorefresh","globalStatePath","precision","setter","useGlobalState","useEffect","timerId","update","old","neu","Math","abs"],"sources":["../../../../src/shared/utils/time.js"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"time.js","names":["dayjs","SEC_MS","MIN_MS","HOUR_MS","DAY_MS","YEAR_MS","now","Date","timer","timeout","res","Barrier","id","setTimeout","resolve","bind","abort","clearTimeout","noop","useCurrent","autorefresh","globalStatePath","precision","setter","useGlobalState","useEffect","timerId","update","old","neu","Math","abs","useTimezoneOffset","cookieName","ssrContext","getSsrContext","offset","setOffset","useState","value","req","cookies","parseInt","date","getTimezoneOffset","document","cookie","Cookie","serialize","path"],"sources":["../../../../src/shared/utils/time.js"],"sourcesContent":["/* global document */\n\nimport Cookie from 'cookie';\nimport dayjs from 'dayjs';\nimport { noop } from 'lodash';\nimport { useEffect, useState } from 'react';\n\nimport { getSsrContext, useGlobalState } from '@dr.pogodin/react-global-state';\n\nimport { Barrier } from './Barrier';\n\n/**\n * @static\n * @const SEC_MS\n * @desc One second, expressed in milliseconds (equals 1000 ms).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.SEC_MS); // Prints: 1000\n */\ndayjs.SEC_MS = 1000;\n\n/**\n * @static\n * @const MIN_MS\n * @desc One minute, expressed in milliseconds (equals 60 × `SEC_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.MIN_MS); // Prints: 60000\n */\ndayjs.MIN_MS = 60 * dayjs.SEC_MS;\n\n/**\n * @static\n * @const HOUR_MS\n * @desc One hour, expressed in milliseconds (equals 60 × `MIN_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.HOUR_MS); // Prints: 3600000\n */\ndayjs.HOUR_MS = 60 * dayjs.MIN_MS;\n\n/**\n * @static\n * @const DAY_MS\n * @desc One day, expressed in milliseconds (equals 24 × `HOUR_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.DAY_MS); // Prints: 86400000\n */\ndayjs.DAY_MS = 24 * dayjs.HOUR_MS;\n\n/**\n * @static\n * @const YEAR_MS\n * @desc One year, expressed in milliseconds (equals 365 × `DAY_MS`,\n * thus a normal, non-leap year).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.YEAR_MS); // Prints: 31536000000\n */\ndayjs.YEAR_MS = 365 * dayjs.DAY_MS;\n\n/**\n * @static\n * @func now\n * @desc Returns Unix timestamp [ms] (thus, it is just an alias for `Date.now`).\n * @return {number}\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.now()); // Prints the current timestamp, e.g. 1618608761000.\n */\ndayjs.now = Date.now;\n\n/**\n * Creates a Promise, which resolves after the given timeout.\n * @param {number} timeout Timeout [ms].\n * @return {Barrier} Resolves after the timeout. It has additional\n * .abort() method attached, which cancels the pending timer resolution\n * (without resolving or rejecting the barrier).\n */\nexport async function timer(timeout) {\n const res = new Barrier();\n if (timeout > 0) {\n const id = setTimeout(res.resolve.bind(res), timeout);\n res.abort = () => clearTimeout(id);\n } else {\n res.abort = noop;\n res.resolve();\n }\n return res;\n}\n\n/**\n * This react hook wraps Date.now() function in a SSR friendly way,\n * ensuring that all calls to useCurrent() within the same render return\n * exactly the same time (which is retrieved from Date.now() first, and\n * then stored in the global state to be reused in all other calls), which\n * is also passed and used in the first client side render, and then updated\n * with a finite precision to avoid infinite re-rendering loops.\n * @param {object} [options] Optional settings.\n * @param {string} [options.globalStatePath=\"currentTime\"] Global state path\n * to keep the current time value.\n * @param {number} [options.precision= 5 * time.SEC_MS] Current time precision.\n * The hook won't update the current time stored in the global state unless it\n * is different from Date.now() result by this number (in milliseconds).\n * Default to 5 seconds.\n * @param {boolean} [options.autorefresh=false] Set `true` to automatically\n * refresh time stored in the global state with the given `precision` (and\n * thus automatically re-rendering components dependent on this hook, or\n * the global state with the period equal to the `precision`.\n * @return {number} Unix timestamp in milliseconds.\n */\nexport function useCurrent({\n autorefresh = false,\n globalStatePath = 'currentTime',\n precision = 5 * dayjs.SEC_MS,\n} = {}) {\n const [now, setter] = useGlobalState(globalStatePath, Date.now);\n useEffect(() => {\n let timerId;\n const update = () => {\n setter((old) => {\n const neu = Date.now();\n return Math.abs(neu - old) > precision ? neu : old;\n });\n if (autorefresh) timerId = setTimeout(update, precision);\n };\n update();\n return () => {\n if (timerId) clearTimeout(timerId);\n };\n }, [autorefresh, precision, setter]);\n return now;\n}\n\n/**\n * Returns client's timezone offset (the difference, in milliseconds, between\n * a timestamp evaluated in the user's timezone, and the same moment of time\n * represented as a standard timestamp in UTC timzone) in an SSR-friendly way,\n * i.e. adding the result of this hook to a standard timestamp will shift it\n * in such way that when formatted to a human-readable form it will represent\n * the time in the user's timezone.\n *\n * Technically, on the first ever call at the server-side it returns zero,\n * then at the client side it initially returns zero, then determines the actual\n * timezone offset, returns it from the hook and also sets it as a cookie.\n * Subsequent renders on the server side will use that cookie to report\n * the user's timezone right away.\n *\n * @param {object} [options] Optional settings.\n * @param {string} [options.cookieName=\"timezoneOffset\"] Optional. The name of\n * cookie to use to store the timezone offset. Defaults \"timezoneOffset\". Set\n * to a falsy value to forbid using cookies altogether (in that case the hook\n * will always return zero value at the server-side, and in the first render\n * at the client-side).\n * @return {number} Timezone offset.\n */\nexport function useTimezoneOffset({\n cookieName = 'timezoneOffset',\n} = {}) {\n const ssrContext = getSsrContext(false);\n const [offset, setOffset] = useState(() => {\n const value = cookieName && ssrContext?.req?.cookies?.[cookieName];\n return value ? parseInt(value, 10) : 0;\n });\n useEffect(() => {\n const date = new Date();\n const value = -date.getTimezoneOffset() * dayjs.MIN_MS;\n setOffset(value);\n if (cookieName) {\n document.cookie = Cookie.serialize(cookieName, value, { path: '/' });\n }\n }, [cookieName]);\n return offset;\n}\n\ndayjs.timer = timer;\ndayjs.useCurrent = useCurrent;\ndayjs.useTimezoneOffset = useTimezoneOffset;\n\nexport default dayjs;\n"],"mappings":";;;;;;;;;;AAEA;AACA;AACA;AACA;AAEA;AAEA;AATA;;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAA,cAAK,CAACC,MAAM,GAAG,IAAI;;AAEnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAD,cAAK,CAACE,MAAM,GAAG,EAAE,GAAGF,cAAK,CAACC,MAAM;;AAEhC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAD,cAAK,CAACG,OAAO,GAAG,EAAE,GAAGH,cAAK,CAACE,MAAM;;AAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAF,cAAK,CAACI,MAAM,GAAG,EAAE,GAAGJ,cAAK,CAACG,OAAO;;AAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAH,cAAK,CAACK,OAAO,GAAG,GAAG,GAAGL,cAAK,CAACI,MAAM;;AAElC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAJ,cAAK,CAACM,GAAG,GAAGC,IAAI,CAACD,GAAG;;AAEpB;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeE,KAAK,CAACC,OAAO,EAAE;EACnC,MAAMC,GAAG,GAAG,IAAIC,gBAAO,EAAE;EACzB,IAAIF,OAAO,GAAG,CAAC,EAAE;IACf,MAAMG,EAAE,GAAGC,UAAU,CAACH,GAAG,CAACI,OAAO,CAACC,IAAI,CAACL,GAAG,CAAC,EAAED,OAAO,CAAC;IACrDC,GAAG,CAACM,KAAK,GAAG,MAAMC,YAAY,CAACL,EAAE,CAAC;EACpC,CAAC,MAAM;IACLF,GAAG,CAACM,KAAK,GAAGE,YAAI;IAChBR,GAAG,CAACI,OAAO,EAAE;EACf;EACA,OAAOJ,GAAG;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASS,UAAU,CAAC;EACzBC,WAAW,GAAG,KAAK;EACnBC,eAAe,GAAG,aAAa;EAC/BC,SAAS,GAAG,CAAC,GAAGtB,cAAK,CAACC;AACxB,CAAC,GAAG,CAAC,CAAC,EAAE;EACN,MAAM,CAACK,GAAG,EAAEiB,MAAM,CAAC,GAAG,IAAAC,gCAAc,EAACH,eAAe,EAAEd,IAAI,CAACD,GAAG,CAAC;EAC/D,IAAAmB,gBAAS,EAAC,MAAM;IACd,IAAIC,OAAO;IACX,MAAMC,MAAM,GAAG,MAAM;MACnBJ,MAAM,CAAEK,GAAG,IAAK;QACd,MAAMC,GAAG,GAAGtB,IAAI,CAACD,GAAG,EAAE;QACtB,OAAOwB,IAAI,CAACC,GAAG,CAACF,GAAG,GAAGD,GAAG,CAAC,GAAGN,SAAS,GAAGO,GAAG,GAAGD,GAAG;MACpD,CAAC,CAAC;MACF,IAAIR,WAAW,EAAEM,OAAO,GAAGb,UAAU,CAACc,MAAM,EAAEL,SAAS,CAAC;IAC1D,CAAC;IACDK,MAAM,EAAE;IACR,OAAO,MAAM;MACX,IAAID,OAAO,EAAET,YAAY,CAACS,OAAO,CAAC;IACpC,CAAC;EACH,CAAC,EAAE,CAACN,WAAW,EAAEE,SAAS,EAAEC,MAAM,CAAC,CAAC;EACpC,OAAOjB,GAAG;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS0B,iBAAiB,CAAC;EAChCC,UAAU,GAAG;AACf,CAAC,GAAG,CAAC,CAAC,EAAE;EACN,MAAMC,UAAU,GAAG,IAAAC,+BAAa,EAAC,KAAK,CAAC;EACvC,MAAM,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAG,IAAAC,eAAQ,EAAC,MAAM;IACzC,MAAMC,KAAK,GAAGN,UAAU,IAAIC,UAAU,EAAEM,GAAG,EAAEC,OAAO,GAAGR,UAAU,CAAC;IAClE,OAAOM,KAAK,GAAGG,QAAQ,CAACH,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC;EACxC,CAAC,CAAC;EACF,IAAAd,gBAAS,EAAC,MAAM;IACd,MAAMkB,IAAI,GAAG,IAAIpC,IAAI,EAAE;IACvB,MAAMgC,KAAK,GAAG,CAACI,IAAI,CAACC,iBAAiB,EAAE,GAAG5C,cAAK,CAACE,MAAM;IACtDmC,SAAS,CAACE,KAAK,CAAC;IAChB,IAAIN,UAAU,EAAE;MACdY,QAAQ,CAACC,MAAM,GAAGC,eAAM,CAACC,SAAS,CAACf,UAAU,EAAEM,KAAK,EAAE;QAAEU,IAAI,EAAE;MAAI,CAAC,CAAC;IACtE;EACF,CAAC,EAAE,CAAChB,UAAU,CAAC,CAAC;EAChB,OAAOG,MAAM;AACf;AAEApC,cAAK,CAACQ,KAAK,GAAGA,KAAK;AACnBR,cAAK,CAACmB,UAAU,GAAGA,UAAU;AAC7BnB,cAAK,CAACgC,iBAAiB,GAAGA,iBAAiB;AAAC,eAE7BhC,cAAK;AAAA"}
|
|
@@ -464,8 +464,8 @@ body {
|
|
|
464
464
|
}
|
|
465
465
|
@media (max-width: 1280px) {
|
|
466
466
|
*.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___container___gyZ4rc,
|
|
467
|
-
.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___context___Szmbbz.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___container___gyZ4rc,
|
|
468
|
-
.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___ad___Ah-Nsc.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___hoc___Wki41G.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___container___gyZ4rc {
|
|
467
|
+
.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___context___Szmbbz.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___container___gyZ4rc,
|
|
468
|
+
.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___ad___Ah-Nsc.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___hoc___Wki41G.-dr-pogodin-react-utils___src-shared-components-Modal-base-theme___container___gyZ4rc {
|
|
469
469
|
max-width: 95vw;
|
|
470
470
|
}
|
|
471
471
|
}
|
|
@@ -286,7 +286,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
286
286
|
\**********************************/
|
|
287
287
|
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
288
288
|
|
|
289
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"timer\": function() { return /* binding */ timer; },\n/* harmony export */ \"useCurrent\": function() { return /* binding */ useCurrent; }\n/* harmony export */ });\n/* harmony import */ var
|
|
289
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"timer\": function() { return /* binding */ timer; },\n/* harmony export */ \"useCurrent\": function() { return /* binding */ useCurrent; },\n/* harmony export */ \"useTimezoneOffset\": function() { return /* binding */ useTimezoneOffset; }\n/* harmony export */ });\n/* harmony import */ var cookie__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! cookie */ \"./node_modules/cookie/index.js\");\n/* harmony import */ var dayjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! dayjs */ \"dayjs\");\n/* harmony import */ var dayjs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(dayjs__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var lodash__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lodash */ \"lodash\");\n/* harmony import */ var lodash__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(lodash__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _dr_pogodin_react_global_state__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @dr.pogodin/react-global-state */ \"@dr.pogodin/react-global-state\");\n/* harmony import */ var _dr_pogodin_react_global_state__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_dr_pogodin_react_global_state__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _Barrier__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Barrier */ \"./src/shared/utils/Barrier.js\");\n/* global document */\n\n\n\n\n\n\n\n\n/**\n * @static\n * @const SEC_MS\n * @desc One second, expressed in milliseconds (equals 1000 ms).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.SEC_MS); // Prints: 1000\n */\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().SEC_MS) = 1000;\n\n/**\n * @static\n * @const MIN_MS\n * @desc One minute, expressed in milliseconds (equals 60 × `SEC_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.MIN_MS); // Prints: 60000\n */\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().MIN_MS) = 60 * (dayjs__WEBPACK_IMPORTED_MODULE_1___default().SEC_MS);\n\n/**\n * @static\n * @const HOUR_MS\n * @desc One hour, expressed in milliseconds (equals 60 × `MIN_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.HOUR_MS); // Prints: 3600000\n */\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().HOUR_MS) = 60 * (dayjs__WEBPACK_IMPORTED_MODULE_1___default().MIN_MS);\n\n/**\n * @static\n * @const DAY_MS\n * @desc One day, expressed in milliseconds (equals 24 × `HOUR_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.DAY_MS); // Prints: 86400000\n */\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().DAY_MS) = 24 * (dayjs__WEBPACK_IMPORTED_MODULE_1___default().HOUR_MS);\n\n/**\n * @static\n * @const YEAR_MS\n * @desc One year, expressed in milliseconds (equals 365 × `DAY_MS`,\n * thus a normal, non-leap year).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.YEAR_MS); // Prints: 31536000000\n */\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().YEAR_MS) = 365 * (dayjs__WEBPACK_IMPORTED_MODULE_1___default().DAY_MS);\n\n/**\n * @static\n * @func now\n * @desc Returns Unix timestamp [ms] (thus, it is just an alias for `Date.now`).\n * @return {number}\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.now()); // Prints the current timestamp, e.g. 1618608761000.\n */\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().now) = Date.now;\n\n/**\n * Creates a Promise, which resolves after the given timeout.\n * @param {number} timeout Timeout [ms].\n * @return {Barrier} Resolves after the timeout. It has additional\n * .abort() method attached, which cancels the pending timer resolution\n * (without resolving or rejecting the barrier).\n */\nasync function timer(timeout) {\n const res = new _Barrier__WEBPACK_IMPORTED_MODULE_5__.Barrier();\n if (timeout > 0) {\n const id = setTimeout(res.resolve.bind(res), timeout);\n res.abort = () => clearTimeout(id);\n } else {\n res.abort = lodash__WEBPACK_IMPORTED_MODULE_2__.noop;\n res.resolve();\n }\n return res;\n}\n\n/**\n * This react hook wraps Date.now() function in a SSR friendly way,\n * ensuring that all calls to useCurrent() within the same render return\n * exactly the same time (which is retrieved from Date.now() first, and\n * then stored in the global state to be reused in all other calls), which\n * is also passed and used in the first client side render, and then updated\n * with a finite precision to avoid infinite re-rendering loops.\n * @param {object} [options] Optional settings.\n * @param {string} [options.globalStatePath=\"currentTime\"] Global state path\n * to keep the current time value.\n * @param {number} [options.precision= 5 * time.SEC_MS] Current time precision.\n * The hook won't update the current time stored in the global state unless it\n * is different from Date.now() result by this number (in milliseconds).\n * Default to 5 seconds.\n * @param {boolean} [options.autorefresh=false] Set `true` to automatically\n * refresh time stored in the global state with the given `precision` (and\n * thus automatically re-rendering components dependent on this hook, or\n * the global state with the period equal to the `precision`.\n * @return {number} Unix timestamp in milliseconds.\n */\nfunction useCurrent() {\n let {\n autorefresh = false,\n globalStatePath = 'currentTime',\n precision = 5 * (dayjs__WEBPACK_IMPORTED_MODULE_1___default().SEC_MS)\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const [now, setter] = (0,_dr_pogodin_react_global_state__WEBPACK_IMPORTED_MODULE_4__.useGlobalState)(globalStatePath, Date.now);\n (0,react__WEBPACK_IMPORTED_MODULE_3__.useEffect)(() => {\n let timerId;\n const update = () => {\n setter(old => {\n const neu = Date.now();\n return Math.abs(neu - old) > precision ? neu : old;\n });\n if (autorefresh) timerId = setTimeout(update, precision);\n };\n update();\n return () => {\n if (timerId) clearTimeout(timerId);\n };\n }, [autorefresh, precision, setter]);\n return now;\n}\n\n/**\n * Returns client's timezone offset (the difference, in milliseconds, between\n * a timestamp evaluated in the user's timezone, and the same moment of time\n * represented as a standard timestamp in UTC timzone) in an SSR-friendly way,\n * i.e. adding the result of this hook to a standard timestamp will shift it\n * in such way that when formatted to a human-readable form it will represent\n * the time in the user's timezone.\n *\n * Technically, on the first ever call at the server-side it returns zero,\n * then at the client side it initially returns zero, then determines the actual\n * timezone offset, returns it from the hook and also sets it as a cookie.\n * Subsequent renders on the server side will use that cookie to report\n * the user's timezone right away.\n *\n * @param {object} [options] Optional settings.\n * @param {string} [options.cookieName=\"timezoneOffset\"] Optional. The name of\n * cookie to use to store the timezone offset. Defaults \"timezoneOffset\". Set\n * to a falsy value to forbid using cookies altogether (in that case the hook\n * will always return zero value at the server-side, and in the first render\n * at the client-side).\n * @return {number} Timezone offset.\n */\nfunction useTimezoneOffset() {\n let {\n cookieName = 'timezoneOffset'\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const ssrContext = (0,_dr_pogodin_react_global_state__WEBPACK_IMPORTED_MODULE_4__.getSsrContext)(false);\n const [offset, setOffset] = (0,react__WEBPACK_IMPORTED_MODULE_3__.useState)(() => {\n var _ssrContext$req, _ssrContext$req$cooki;\n const value = cookieName && (ssrContext === null || ssrContext === void 0 ? void 0 : (_ssrContext$req = ssrContext.req) === null || _ssrContext$req === void 0 ? void 0 : (_ssrContext$req$cooki = _ssrContext$req.cookies) === null || _ssrContext$req$cooki === void 0 ? void 0 : _ssrContext$req$cooki[cookieName]);\n return value ? parseInt(value, 10) : 0;\n });\n (0,react__WEBPACK_IMPORTED_MODULE_3__.useEffect)(() => {\n const date = new Date();\n const value = -date.getTimezoneOffset() * (dayjs__WEBPACK_IMPORTED_MODULE_1___default().MIN_MS);\n setOffset(value);\n if (cookieName) {\n document.cookie = cookie__WEBPACK_IMPORTED_MODULE_0__.serialize(cookieName, value, {\n path: '/'\n });\n }\n }, [cookieName]);\n return offset;\n}\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().timer) = timer;\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().useCurrent) = useCurrent;\n(dayjs__WEBPACK_IMPORTED_MODULE_1___default().useTimezoneOffset) = useTimezoneOffset;\n/* harmony default export */ __webpack_exports__[\"default\"] = ((dayjs__WEBPACK_IMPORTED_MODULE_1___default()));\n\n//# sourceURL=webpack://@dr.pogodin/react-utils/./src/shared/utils/time.js?");
|
|
290
290
|
|
|
291
291
|
/***/ }),
|
|
292
292
|
|
|
@@ -300,6 +300,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
300
300
|
|
|
301
301
|
/***/ }),
|
|
302
302
|
|
|
303
|
+
/***/ "./node_modules/cookie/index.js":
|
|
304
|
+
/*!**************************************!*\
|
|
305
|
+
!*** ./node_modules/cookie/index.js ***!
|
|
306
|
+
\**************************************/
|
|
307
|
+
/***/ (function(__unused_webpack_module, exports) {
|
|
308
|
+
|
|
309
|
+
eval("/*!\n * cookie\n * Copyright(c) 2012-2014 Roman Shtylman\n * Copyright(c) 2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n\n\n/**\n * Module exports.\n * @public\n */\n\nexports.parse = parse;\nexports.serialize = serialize;\n\n/**\n * Module variables.\n * @private\n */\n\nvar __toString = Object.prototype.toString\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\n\nvar fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\n/**\n * Parse a cookie header.\n *\n * Parse the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n *\n * @param {string} str\n * @param {object} [options]\n * @return {object}\n * @public\n */\n\nfunction parse(str, options) {\n if (typeof str !== 'string') {\n throw new TypeError('argument str must be a string');\n }\n\n var obj = {}\n var opt = options || {};\n var dec = opt.decode || decode;\n\n var index = 0\n while (index < str.length) {\n var eqIdx = str.indexOf('=', index)\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break\n }\n\n var endIdx = str.indexOf(';', index)\n\n if (endIdx === -1) {\n endIdx = str.length\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(';', eqIdx - 1) + 1\n continue\n }\n\n var key = str.slice(index, eqIdx).trim()\n\n // only assign once\n if (undefined === obj[key]) {\n var val = str.slice(eqIdx + 1, endIdx).trim()\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1)\n }\n\n obj[key] = tryDecode(val, dec);\n }\n\n index = endIdx + 1\n }\n\n return obj;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * serialize('foo', 'bar', { httpOnly: true })\n * => \"foo=bar; httpOnly\"\n *\n * @param {string} name\n * @param {string} val\n * @param {object} [options]\n * @return {string}\n * @public\n */\n\nfunction serialize(name, val, options) {\n var opt = options || {};\n var enc = opt.encode || encode;\n\n if (typeof enc !== 'function') {\n throw new TypeError('option encode is invalid');\n }\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError('argument name is invalid');\n }\n\n var value = enc(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError('argument val is invalid');\n }\n\n var str = name + '=' + value;\n\n if (null != opt.maxAge) {\n var maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError('option maxAge is invalid')\n }\n\n str += '; Max-Age=' + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError('option domain is invalid');\n }\n\n str += '; Domain=' + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError('option path is invalid');\n }\n\n str += '; Path=' + opt.path;\n }\n\n if (opt.expires) {\n var expires = opt.expires\n\n if (!isDate(expires) || isNaN(expires.valueOf())) {\n throw new TypeError('option expires is invalid');\n }\n\n str += '; Expires=' + expires.toUTCString()\n }\n\n if (opt.httpOnly) {\n str += '; HttpOnly';\n }\n\n if (opt.secure) {\n str += '; Secure';\n }\n\n if (opt.priority) {\n var priority = typeof opt.priority === 'string'\n ? opt.priority.toLowerCase()\n : opt.priority\n\n switch (priority) {\n case 'low':\n str += '; Priority=Low'\n break\n case 'medium':\n str += '; Priority=Medium'\n break\n case 'high':\n str += '; Priority=High'\n break\n default:\n throw new TypeError('option priority is invalid')\n }\n }\n\n if (opt.sameSite) {\n var sameSite = typeof opt.sameSite === 'string'\n ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n str += '; SameSite=Strict';\n break;\n case 'lax':\n str += '; SameSite=Lax';\n break;\n case 'strict':\n str += '; SameSite=Strict';\n break;\n case 'none':\n str += '; SameSite=None';\n break;\n default:\n throw new TypeError('option sameSite is invalid');\n }\n }\n\n return str;\n}\n\n/**\n * URL-decode string value. Optimized to skip native call when no %.\n *\n * @param {string} str\n * @returns {string}\n */\n\nfunction decode (str) {\n return str.indexOf('%') !== -1\n ? decodeURIComponent(str)\n : str\n}\n\n/**\n * URL-encode value.\n *\n * @param {string} str\n * @returns {string}\n */\n\nfunction encode (val) {\n return encodeURIComponent(val)\n}\n\n/**\n * Determine if value is a Date.\n *\n * @param {*} val\n * @private\n */\n\nfunction isDate (val) {\n return __toString.call(val) === '[object Date]' ||\n val instanceof Date\n}\n\n/**\n * Try decoding a string using a decoding function.\n *\n * @param {string} str\n * @param {function} decode\n * @private\n */\n\nfunction tryDecode(str, decode) {\n try {\n return decode(str);\n } catch (e) {\n return str;\n }\n}\n\n\n//# sourceURL=webpack://@dr.pogodin/react-utils/./node_modules/cookie/index.js?");
|
|
310
|
+
|
|
311
|
+
/***/ }),
|
|
312
|
+
|
|
303
313
|
/***/ "./src/shared/components/Button/style.scss":
|
|
304
314
|
/*!*************************************************!*\
|
|
305
315
|
!*** ./src/shared/components/Button/style.scss ***!
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.default=factory;exports.getDefaultCspSettings=getDefaultCspSettings;var _path=require("path");var _url=require("url");var _lodash=require("lodash");var _compression=_interopRequireDefault(require("compression"));var _cookieParser=_interopRequireDefault(require("cookie-parser"));var _csurf=_interopRequireDefault(require("csurf"));var _express=_interopRequireDefault(require("express"));var _serveFavicon=_interopRequireDefault(require("serve-favicon"));var _helmet=_interopRequireDefault(require("helmet"));var _morgan=_interopRequireDefault(require("morgan"));var _requestIp=_interopRequireDefault(require("request-ip"));var _uuid=require("uuid");var _renderer=_interopRequireDefault(require("./renderer"));var _errors=require("./utils/errors");/**
|
|
1
|
+
"use strict";var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.default=factory;exports.getDefaultCspSettings=getDefaultCspSettings;var _path=require("path");var _url=require("url");var _lodash=require("lodash");var _compression=_interopRequireDefault(require("compression"));var _cookieParser=_interopRequireDefault(require("cookie-parser"));var _csurf=_interopRequireDefault(require("@dr.pogodin/csurf"));var _express=_interopRequireDefault(require("express"));var _serveFavicon=_interopRequireDefault(require("serve-favicon"));var _helmet=_interopRequireDefault(require("helmet"));var _morgan=_interopRequireDefault(require("morgan"));var _requestIp=_interopRequireDefault(require("request-ip"));var _uuid=require("uuid");var _renderer=_interopRequireDefault(require("./renderer"));var _errors=require("./utils/errors");/**
|
|
2
2
|
* Creation of standard ExpressJS server for ReactJS apps.
|
|
3
3
|
*/ /**
|
|
4
4
|
* Default Content Security Policy settings.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["defaultCspSettings","directives","mapValues","helmet","contentSecurityPolicy","getDefaultDirectives","array","filter","item","push","getDefaultCspSettings","cloneDeep","factory","webpackConfig","options","rendererOps","pick","renderer","rendererFactory","publicPath","output","server","express","beforeExpressJsSetup","logger","httpsRedirect","use","req","res","next","schema","headers","url","host","originalUrl","redirect","compression","crossOriginEmbedderPolicy","crossOriginOpenerPolicy","crossOriginResourcePolicy","noCsp","nonce","uuid","cspNonce","cspSettings","cspSettingsHook","favicon","send","json","limit","urlencoded","extended","cookieParser","requestIp","mw","csrf","cookie","loggerMiddleware","token","clientIp","FORMAT","stream","write","info","bind","get","static","path","setHeaders","set","devMode","global","location","href","pathToFileURL","process","cwd","sep","webpack","require","webpackDevMiddleware","webpackHotMiddleware","compiler","serverSideRender","onExpressJsSetup","newError","ERRORS","NOT_FOUND","CODES","dontAttachDefaultErrorHandler","beforeExpressJsError","error","headersSent","status","INTERNAL_SERVER_ERROR","serverSide","log","message","getErrorForCode","env","NODE_ENV","undefined"],"sources":["../../../src/server/server.js"],"sourcesContent":["/**\n * Creation of standard ExpressJS server for ReactJS apps.\n */\n\nimport { sep } from 'path';\nimport { pathToFileURL } from 'url';\n\nimport {\n cloneDeep,\n mapValues,\n pick,\n} from 'lodash';\n\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport csrf from 'csurf';\nimport express from 'express';\nimport favicon from 'serve-favicon';\nimport helmet from 'helmet';\nimport loggerMiddleware from 'morgan';\nimport requestIp from 'request-ip';\nimport { v4 as uuid } from 'uuid';\n\nimport rendererFactory from './renderer';\n\nimport {\n CODES,\n ERRORS,\n getErrorForCode,\n newError,\n} from './utils/errors';\n\n/**\n * Default Content Security Policy settings.\n * @ignore\n */\nconst defaultCspSettings = {\n directives: mapValues(\n helmet.contentSecurityPolicy.getDefaultDirectives(),\n\n // 'https:' options (automatic re-write of insecure URLs to secure ones)\n // is removed to facilitate local development with HTTP server. In cloud\n // deployments we assume Apache or Nginx server in front of out app takes\n // care about such re-writes.\n (array) => array.filter((item) => item !== 'https:'),\n ),\n};\ndefaultCspSettings.directives['frame-src'] = [\n \"'self'\",\n\n // YouTube domain is whitelisted to allow <YouTubeVideo> component to work\n // out of box.\n 'https://*.youtube.com',\n];\ndefaultCspSettings.directives['script-src'].push(\"'unsafe-eval'\");\n\n// No need for automatic re-writes via Content Security Policy settings:\n// the forefront Apache or Nginx server is supposed to take care of this\n// in production cloud deployments.\ndelete defaultCspSettings.directives['upgrade-insecure-requests'];\n\n/**\n * @category Utilities\n * @func server/getDefaultCspSettings\n * @global\n * @desc\n * ```js\n * import { server } from '@dr.pogodin/react-utils';\n * const { getDefaultCspSettings } from '@dr.pogodin/react-utils';\n * ```\n * @return {{\n * directives: object\n * }} A deep copy of default CSP settings object used by `react-utils`,\n * with the exception of `nonce-xxx` clause in `script-src` directive,\n * which is added dynamically for each request.\n */\nexport function getDefaultCspSettings() {\n return cloneDeep(defaultCspSettings);\n}\n\nexport default async function factory(webpackConfig, options) {\n const rendererOps = pick(options, [\n 'Application',\n 'beforeRender',\n 'favicon',\n 'logger',\n 'maxSsrRounds',\n 'noCsp',\n 'ssrTimeout',\n 'staticCacheController',\n 'staticCacheSize',\n ]);\n const renderer = rendererFactory(webpackConfig, rendererOps);\n const { publicPath } = webpackConfig.output;\n\n const server = express();\n\n if (options.beforeExpressJsSetup) {\n await options.beforeExpressJsSetup(server);\n }\n\n server.logger = options.logger;\n\n if (options.httpsRedirect) {\n server.use((req, res, next) => {\n const schema = req.headers['x-forwarded-proto'];\n if (schema === 'http') {\n let url = `https://${req.headers.host}`;\n if (req.originalUrl !== '/') url += req.originalUrl;\n return res.redirect(url);\n }\n return next();\n });\n }\n\n server.use(compression());\n server.use(\n helmet({\n contentSecurityPolicy: false,\n crossOriginEmbedderPolicy: false,\n crossOriginOpenerPolicy: false,\n crossOriginResourcePolicy: false,\n }),\n );\n\n if (!options.noCsp) {\n server.use((req, res, next) => {\n req.nonce = uuid();\n\n // TODO: This is deprecated, but it is kept for now for backward\n // compatibility. Should be removed sometime later.\n req.cspNonce = req.nonce;\n\n // The deep clone is necessary here to ensure that default value can't be\n // mutated during request processing.\n let cspSettings = cloneDeep(defaultCspSettings);\n cspSettings.directives['script-src'].push(`'nonce-${req.nonce}'`);\n if (options.cspSettingsHook) {\n cspSettings = options.cspSettingsHook(cspSettings, req);\n }\n helmet.contentSecurityPolicy(cspSettings)(req, res, next);\n });\n }\n\n if (options.favicon) {\n server.use(favicon(options.favicon));\n }\n\n server.use('/robots.txt', (req, res) => res.send('User-agent: *\\nDisallow:'));\n\n server.use(express.json({ limit: '300kb' }));\n server.use(express.urlencoded({ extended: false }));\n server.use(cookieParser());\n server.use(requestIp.mw());\n\n server.use(csrf({ cookie: true }));\n\n loggerMiddleware.token('ip', (req) => req.clientIp);\n const FORMAT = ':ip > :status :method :url :response-time ms :res[content-length] :referrer :user-agent';\n server.use(loggerMiddleware(FORMAT, {\n stream: {\n write: options.logger.info.bind(options.logger),\n },\n }));\n\n // Note: no matter the \"public path\", we want the service worker, if any,\n // to be served from the root, to have all web app pages in its scope.\n // Thus, this setup to serve it. Probably, need some more configuration\n // for special cases, but this will do for now.\n server.get('/__service-worker.js', express.static(\n webpackConfig.output.path,\n {\n setHeaders: (res) => res.set('Cache-Control', 'no-cache'),\n },\n ));\n\n /* Setup of Hot Module Reloading for development environment.\n * These dependencies are not used, nor installed for production use,\n * hence we should violate some import-related lint rules. */\n /* eslint-disable global-require */\n /* eslint-disable import/no-extraneous-dependencies */\n /* eslint-disable import/no-unresolved */\n if (options.devMode) {\n // This is a workaround for SASS bug:\n // https://github.com/dart-lang/sdk/issues/27979\n // which manifests itself sometimes when webpack dev middleware is used\n // (in dev mode), and app modules are imported in some unfortunate ways.\n if (!global.location) {\n global.location = {\n href: `${pathToFileURL(process.cwd()).href}${sep}`,\n };\n }\n\n const webpack = require('webpack');\n const webpackDevMiddleware = require('webpack-dev-middleware');\n const webpackHotMiddleware = require('webpack-hot-middleware');\n const compiler = webpack(webpackConfig);\n server.use(webpackDevMiddleware(compiler, {\n publicPath,\n serverSideRender: true,\n }));\n server.use(webpackHotMiddleware(compiler));\n }\n /* eslint-enable global-require */\n /* eslint-enable import/no-extraneous-dependencies */\n /* eslint-enable import/no-unresolved */\n\n server.use(publicPath, express.static(webpackConfig.output.path));\n\n if (options.onExpressJsSetup) {\n await options.onExpressJsSetup(server);\n }\n server.use(renderer);\n\n /* Detects 404 errors, and forwards them to the error handler. */\n server.use((req, res, next) => {\n next(newError(ERRORS.NOT_FOUND, CODES.NOT_FOUND));\n });\n\n let dontAttachDefaultErrorHandler;\n if (options.beforeExpressJsError) {\n dontAttachDefaultErrorHandler = await options.beforeExpressJsError(server);\n }\n\n /* Error handler. */\n if (!dontAttachDefaultErrorHandler) {\n // TODO: Do we need this error handler at all? It actually seems to do\n // what the default ExpressJS error handler does anyway, see:\n // https://expressjs.com/en/guide/error-handling.html\n //\n // TODO: It is better to move the default error handler definition\n // to a stand-alone function at top-level, but the use of options.logger\n // prevents to do it without some extra refactoring. Should be done sometime\n // though.\n server.use((error, req, res, next) => {\n // TODO: This is needed to correctly handled any errors thrown after\n // sending initial response to the client.\n if (res.headersSent) return next(error);\n\n const status = error.status || CODES.INTERNAL_SERVER_ERROR;\n const serverSide = status >= CODES.INTERNAL_SERVER_ERROR;\n\n // Log server-side errors always, client-side at debug level only.\n options.logger.log(serverSide ? 'error' : 'debug', error);\n\n let message = error.message || getErrorForCode(status);\n if (serverSide && process.env.NODE_ENV === 'production') {\n message = ERRORS.INTERNAL_SERVER_ERROR;\n }\n\n res.status(status).send(message);\n return undefined;\n });\n }\n\n return server;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":["defaultCspSettings","directives","mapValues","helmet","contentSecurityPolicy","getDefaultDirectives","array","filter","item","push","getDefaultCspSettings","cloneDeep","factory","webpackConfig","options","rendererOps","pick","renderer","rendererFactory","publicPath","output","server","express","beforeExpressJsSetup","logger","httpsRedirect","use","req","res","next","schema","headers","url","host","originalUrl","redirect","compression","crossOriginEmbedderPolicy","crossOriginOpenerPolicy","crossOriginResourcePolicy","noCsp","nonce","uuid","cspNonce","cspSettings","cspSettingsHook","favicon","send","json","limit","urlencoded","extended","cookieParser","requestIp","mw","csrf","cookie","loggerMiddleware","token","clientIp","FORMAT","stream","write","info","bind","get","static","path","setHeaders","set","devMode","global","location","href","pathToFileURL","process","cwd","sep","webpack","require","webpackDevMiddleware","webpackHotMiddleware","compiler","serverSideRender","onExpressJsSetup","newError","ERRORS","NOT_FOUND","CODES","dontAttachDefaultErrorHandler","beforeExpressJsError","error","headersSent","status","INTERNAL_SERVER_ERROR","serverSide","log","message","getErrorForCode","env","NODE_ENV","undefined"],"sources":["../../../src/server/server.js"],"sourcesContent":["/**\n * Creation of standard ExpressJS server for ReactJS apps.\n */\n\nimport { sep } from 'path';\nimport { pathToFileURL } from 'url';\n\nimport {\n cloneDeep,\n mapValues,\n pick,\n} from 'lodash';\n\nimport compression from 'compression';\nimport cookieParser from 'cookie-parser';\nimport csrf from '@dr.pogodin/csurf';\nimport express from 'express';\nimport favicon from 'serve-favicon';\nimport helmet from 'helmet';\nimport loggerMiddleware from 'morgan';\nimport requestIp from 'request-ip';\nimport { v4 as uuid } from 'uuid';\n\nimport rendererFactory from './renderer';\n\nimport {\n CODES,\n ERRORS,\n getErrorForCode,\n newError,\n} from './utils/errors';\n\n/**\n * Default Content Security Policy settings.\n * @ignore\n */\nconst defaultCspSettings = {\n directives: mapValues(\n helmet.contentSecurityPolicy.getDefaultDirectives(),\n\n // 'https:' options (automatic re-write of insecure URLs to secure ones)\n // is removed to facilitate local development with HTTP server. In cloud\n // deployments we assume Apache or Nginx server in front of out app takes\n // care about such re-writes.\n (array) => array.filter((item) => item !== 'https:'),\n ),\n};\ndefaultCspSettings.directives['frame-src'] = [\n \"'self'\",\n\n // YouTube domain is whitelisted to allow <YouTubeVideo> component to work\n // out of box.\n 'https://*.youtube.com',\n];\ndefaultCspSettings.directives['script-src'].push(\"'unsafe-eval'\");\n\n// No need for automatic re-writes via Content Security Policy settings:\n// the forefront Apache or Nginx server is supposed to take care of this\n// in production cloud deployments.\ndelete defaultCspSettings.directives['upgrade-insecure-requests'];\n\n/**\n * @category Utilities\n * @func server/getDefaultCspSettings\n * @global\n * @desc\n * ```js\n * import { server } from '@dr.pogodin/react-utils';\n * const { getDefaultCspSettings } from '@dr.pogodin/react-utils';\n * ```\n * @return {{\n * directives: object\n * }} A deep copy of default CSP settings object used by `react-utils`,\n * with the exception of `nonce-xxx` clause in `script-src` directive,\n * which is added dynamically for each request.\n */\nexport function getDefaultCspSettings() {\n return cloneDeep(defaultCspSettings);\n}\n\nexport default async function factory(webpackConfig, options) {\n const rendererOps = pick(options, [\n 'Application',\n 'beforeRender',\n 'favicon',\n 'logger',\n 'maxSsrRounds',\n 'noCsp',\n 'ssrTimeout',\n 'staticCacheController',\n 'staticCacheSize',\n ]);\n const renderer = rendererFactory(webpackConfig, rendererOps);\n const { publicPath } = webpackConfig.output;\n\n const server = express();\n\n if (options.beforeExpressJsSetup) {\n await options.beforeExpressJsSetup(server);\n }\n\n server.logger = options.logger;\n\n if (options.httpsRedirect) {\n server.use((req, res, next) => {\n const schema = req.headers['x-forwarded-proto'];\n if (schema === 'http') {\n let url = `https://${req.headers.host}`;\n if (req.originalUrl !== '/') url += req.originalUrl;\n return res.redirect(url);\n }\n return next();\n });\n }\n\n server.use(compression());\n server.use(\n helmet({\n contentSecurityPolicy: false,\n crossOriginEmbedderPolicy: false,\n crossOriginOpenerPolicy: false,\n crossOriginResourcePolicy: false,\n }),\n );\n\n if (!options.noCsp) {\n server.use((req, res, next) => {\n req.nonce = uuid();\n\n // TODO: This is deprecated, but it is kept for now for backward\n // compatibility. Should be removed sometime later.\n req.cspNonce = req.nonce;\n\n // The deep clone is necessary here to ensure that default value can't be\n // mutated during request processing.\n let cspSettings = cloneDeep(defaultCspSettings);\n cspSettings.directives['script-src'].push(`'nonce-${req.nonce}'`);\n if (options.cspSettingsHook) {\n cspSettings = options.cspSettingsHook(cspSettings, req);\n }\n helmet.contentSecurityPolicy(cspSettings)(req, res, next);\n });\n }\n\n if (options.favicon) {\n server.use(favicon(options.favicon));\n }\n\n server.use('/robots.txt', (req, res) => res.send('User-agent: *\\nDisallow:'));\n\n server.use(express.json({ limit: '300kb' }));\n server.use(express.urlencoded({ extended: false }));\n server.use(cookieParser());\n server.use(requestIp.mw());\n\n server.use(csrf({ cookie: true }));\n\n loggerMiddleware.token('ip', (req) => req.clientIp);\n const FORMAT = ':ip > :status :method :url :response-time ms :res[content-length] :referrer :user-agent';\n server.use(loggerMiddleware(FORMAT, {\n stream: {\n write: options.logger.info.bind(options.logger),\n },\n }));\n\n // Note: no matter the \"public path\", we want the service worker, if any,\n // to be served from the root, to have all web app pages in its scope.\n // Thus, this setup to serve it. Probably, need some more configuration\n // for special cases, but this will do for now.\n server.get('/__service-worker.js', express.static(\n webpackConfig.output.path,\n {\n setHeaders: (res) => res.set('Cache-Control', 'no-cache'),\n },\n ));\n\n /* Setup of Hot Module Reloading for development environment.\n * These dependencies are not used, nor installed for production use,\n * hence we should violate some import-related lint rules. */\n /* eslint-disable global-require */\n /* eslint-disable import/no-extraneous-dependencies */\n /* eslint-disable import/no-unresolved */\n if (options.devMode) {\n // This is a workaround for SASS bug:\n // https://github.com/dart-lang/sdk/issues/27979\n // which manifests itself sometimes when webpack dev middleware is used\n // (in dev mode), and app modules are imported in some unfortunate ways.\n if (!global.location) {\n global.location = {\n href: `${pathToFileURL(process.cwd()).href}${sep}`,\n };\n }\n\n const webpack = require('webpack');\n const webpackDevMiddleware = require('webpack-dev-middleware');\n const webpackHotMiddleware = require('webpack-hot-middleware');\n const compiler = webpack(webpackConfig);\n server.use(webpackDevMiddleware(compiler, {\n publicPath,\n serverSideRender: true,\n }));\n server.use(webpackHotMiddleware(compiler));\n }\n /* eslint-enable global-require */\n /* eslint-enable import/no-extraneous-dependencies */\n /* eslint-enable import/no-unresolved */\n\n server.use(publicPath, express.static(webpackConfig.output.path));\n\n if (options.onExpressJsSetup) {\n await options.onExpressJsSetup(server);\n }\n server.use(renderer);\n\n /* Detects 404 errors, and forwards them to the error handler. */\n server.use((req, res, next) => {\n next(newError(ERRORS.NOT_FOUND, CODES.NOT_FOUND));\n });\n\n let dontAttachDefaultErrorHandler;\n if (options.beforeExpressJsError) {\n dontAttachDefaultErrorHandler = await options.beforeExpressJsError(server);\n }\n\n /* Error handler. */\n if (!dontAttachDefaultErrorHandler) {\n // TODO: Do we need this error handler at all? It actually seems to do\n // what the default ExpressJS error handler does anyway, see:\n // https://expressjs.com/en/guide/error-handling.html\n //\n // TODO: It is better to move the default error handler definition\n // to a stand-alone function at top-level, but the use of options.logger\n // prevents to do it without some extra refactoring. Should be done sometime\n // though.\n server.use((error, req, res, next) => {\n // TODO: This is needed to correctly handled any errors thrown after\n // sending initial response to the client.\n if (res.headersSent) return next(error);\n\n const status = error.status || CODES.INTERNAL_SERVER_ERROR;\n const serverSide = status >= CODES.INTERNAL_SERVER_ERROR;\n\n // Log server-side errors always, client-side at debug level only.\n options.logger.log(serverSide ? 'error' : 'debug', error);\n\n let message = error.message || getErrorForCode(status);\n if (serverSide && process.env.NODE_ENV === 'production') {\n message = ERRORS.INTERNAL_SERVER_ERROR;\n }\n\n res.status(status).send(message);\n return undefined;\n });\n }\n\n return server;\n}\n"],"mappings":"qOAIA,0BACA,wBAEA,8BAMA,gEACA,mEACA,gEACA,wDACA,mEACA,sDACA,sDACA,6DACA,0BAEA,4DAEA,sCAzBA;AACA;AACA,GAFA,CAgCA;AACA;AACA;AACA,GACA,KAAMA,mBAAkB,CAAG,CACzBC,UAAU,CAAE,GAAAC,iBAAS,EACnBC,eAAM,CAACC,qBAAqB,CAACC,oBAAoB,EAAE,CAEnD;AACA;AACA;AACA;AACCC,KAAK,EAAKA,KAAK,CAACC,MAAM,CAAEC,IAAI,EAAKA,IAAI,GAAK,QAAQ,CAAC,CAExD,CAAC,CACDR,kBAAkB,CAACC,UAAU,CAAC,WAAW,CAAC,CAAG,CAC3C,QAAQ,CAER;AACA;AACA,uBAAuB,CACxB,CACDD,kBAAkB,CAACC,UAAU,CAAC,YAAY,CAAC,CAACQ,IAAI,CAAC,eAAe,CAAC,CAEjE;AACA;AACA;AACA,MAAOT,mBAAkB,CAACC,UAAU,CAAC,2BAA2B,CAAC,CAEjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACO,QAASS,sBAAqB,EAAG,CACtC,MAAO,GAAAC,iBAAS,EAACX,kBAAkB,CACrC,CAEe,cAAeY,QAAO,CAACC,aAAa,CAAEC,OAAO,CAAE,CAC5D,KAAMC,YAAW,CAAG,GAAAC,YAAI,EAACF,OAAO,CAAE,CAChC,aAAa,CACb,cAAc,CACd,SAAS,CACT,QAAQ,CACR,cAAc,CACd,OAAO,CACP,YAAY,CACZ,uBAAuB,CACvB,iBAAiB,CAClB,CAAC,CACF,KAAMG,SAAQ,CAAG,GAAAC,iBAAe,EAACL,aAAa,CAAEE,WAAW,CAAC,CAC5D,KAAM,CAAEI,UAAW,CAAC,CAAGN,aAAa,CAACO,MAAM,CAE3C,KAAMC,OAAM,CAAG,GAAAC,gBAAO,GAAE,CAExB,GAAIR,OAAO,CAACS,oBAAoB,CAAE,CAChC,KAAMT,QAAO,CAACS,oBAAoB,CAACF,MAAM,CAC3C,CAEAA,MAAM,CAACG,MAAM,CAAGV,OAAO,CAACU,MAAM,CAE9B,GAAIV,OAAO,CAACW,aAAa,CAAE,CACzBJ,MAAM,CAACK,GAAG,CAAC,CAACC,GAAG,CAAEC,GAAG,CAAEC,IAAI,GAAK,CAC7B,KAAMC,OAAM,CAAGH,GAAG,CAACI,OAAO,CAAC,mBAAmB,CAAC,CAC/C,GAAID,MAAM,GAAK,MAAM,CAAE,CACrB,GAAIE,IAAG,CAAI,WAAUL,GAAG,CAACI,OAAO,CAACE,IAAK,EAAC,CACvC,GAAIN,GAAG,CAACO,WAAW,GAAK,GAAG,CAAEF,GAAG,EAAIL,GAAG,CAACO,WAAW,CACnD,MAAON,IAAG,CAACO,QAAQ,CAACH,GAAG,CACzB,CACA,MAAOH,KAAI,EACb,CAAC,CACH,CAEAR,MAAM,CAACK,GAAG,CAAC,GAAAU,oBAAW,GAAE,CAAC,CACzBf,MAAM,CAACK,GAAG,CACR,GAAAvB,eAAM,EAAC,CACLC,qBAAqB,CAAE,KAAK,CAC5BiC,yBAAyB,CAAE,KAAK,CAChCC,uBAAuB,CAAE,KAAK,CAC9BC,yBAAyB,CAAE,KAC7B,CAAC,CAAC,CACH,CAED,GAAI,CAACzB,OAAO,CAAC0B,KAAK,CAAE,CAClBnB,MAAM,CAACK,GAAG,CAAC,CAACC,GAAG,CAAEC,GAAG,CAAEC,IAAI,GAAK,CAC7BF,GAAG,CAACc,KAAK,CAAG,GAAAC,QAAI,GAAE,CAElB;AACA;AACAf,GAAG,CAACgB,QAAQ,CAAGhB,GAAG,CAACc,KAAK,CAExB;AACA;AACA,GAAIG,YAAW,CAAG,GAAAjC,iBAAS,EAACX,kBAAkB,CAAC,CAC/C4C,WAAW,CAAC3C,UAAU,CAAC,YAAY,CAAC,CAACQ,IAAI,CAAE,UAASkB,GAAG,CAACc,KAAM,GAAE,CAAC,CACjE,GAAI3B,OAAO,CAAC+B,eAAe,CAAE,CAC3BD,WAAW,CAAG9B,OAAO,CAAC+B,eAAe,CAACD,WAAW,CAAEjB,GAAG,CACxD,CACAxB,eAAM,CAACC,qBAAqB,CAACwC,WAAW,CAAC,CAACjB,GAAG,CAAEC,GAAG,CAAEC,IAAI,CAC1D,CAAC,CACH,CAEA,GAAIf,OAAO,CAACgC,OAAO,CAAE,CACnBzB,MAAM,CAACK,GAAG,CAAC,GAAAoB,qBAAO,EAAChC,OAAO,CAACgC,OAAO,CAAC,CACrC,CAEAzB,MAAM,CAACK,GAAG,CAAC,aAAa,CAAE,CAACC,GAAG,CAAEC,GAAG,GAAKA,GAAG,CAACmB,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAE7E1B,MAAM,CAACK,GAAG,CAACJ,gBAAO,CAAC0B,IAAI,CAAC,CAAEC,KAAK,CAAE,OAAQ,CAAC,CAAC,CAAC,CAC5C5B,MAAM,CAACK,GAAG,CAACJ,gBAAO,CAAC4B,UAAU,CAAC,CAAEC,QAAQ,CAAE,KAAM,CAAC,CAAC,CAAC,CACnD9B,MAAM,CAACK,GAAG,CAAC,GAAA0B,qBAAY,GAAE,CAAC,CAC1B/B,MAAM,CAACK,GAAG,CAAC2B,kBAAS,CAACC,EAAE,EAAE,CAAC,CAE1BjC,MAAM,CAACK,GAAG,CAAC,GAAA6B,cAAI,EAAC,CAAEC,MAAM,CAAE,IAAK,CAAC,CAAC,CAAC,CAElCC,eAAgB,CAACC,KAAK,CAAC,IAAI,CAAG/B,GAAG,EAAKA,GAAG,CAACgC,QAAQ,CAAC,CACnD,KAAMC,OAAM,CAAG,yFAAyF,CACxGvC,MAAM,CAACK,GAAG,CAAC,GAAA+B,eAAgB,EAACG,MAAM,CAAE,CAClCC,MAAM,CAAE,CACNC,KAAK,CAAEhD,OAAO,CAACU,MAAM,CAACuC,IAAI,CAACC,IAAI,CAAClD,OAAO,CAACU,MAAM,CAChD,CACF,CAAC,CAAC,CAAC,CAEH;AACA;AACA;AACA;AACAH,MAAM,CAAC4C,GAAG,CAAC,sBAAsB,CAAE3C,gBAAO,CAAC4C,MAAM,CAC/CrD,aAAa,CAACO,MAAM,CAAC+C,IAAI,CACzB,CACEC,UAAU,CAAGxC,GAAG,EAAKA,GAAG,CAACyC,GAAG,CAAC,eAAe,CAAE,UAAU,CAC1D,CAAC,CACF,CAAC,CAEF;AACF;AACA,+DAFE,CAGA,oCACA,uDACA,yCACA,GAAIvD,OAAO,CAACwD,OAAO,CAAE,CACnB;AACA;AACA;AACA;AACA,GAAI,CAACC,MAAM,CAACC,QAAQ,CAAE,CACpBD,MAAM,CAACC,QAAQ,CAAG,CAChBC,IAAI,CAAG,GAAE,GAAAC,kBAAa,EAACC,OAAO,CAACC,GAAG,EAAE,CAAC,CAACH,IAAK,GAAEI,SAAI,EACnD,CACF,CAEA,KAAMC,QAAO,CAAGC,OAAO,CAAC,SAAS,CAAC,CAClC,KAAMC,qBAAoB,CAAGD,OAAO,CAAC,wBAAwB,CAAC,CAC9D,KAAME,qBAAoB,CAAGF,OAAO,CAAC,wBAAwB,CAAC,CAC9D,KAAMG,SAAQ,CAAGJ,OAAO,CAACjE,aAAa,CAAC,CACvCQ,MAAM,CAACK,GAAG,CAACsD,oBAAoB,CAACE,QAAQ,CAAE,CACxC/D,UAAU,CACVgE,gBAAgB,CAAE,IACpB,CAAC,CAAC,CAAC,CACH9D,MAAM,CAACK,GAAG,CAACuD,oBAAoB,CAACC,QAAQ,CAAC,CAC3C,CACA,mCACA,sDACA,wCAEA7D,MAAM,CAACK,GAAG,CAACP,UAAU,CAAEG,gBAAO,CAAC4C,MAAM,CAACrD,aAAa,CAACO,MAAM,CAAC+C,IAAI,CAAC,CAAC,CAEjE,GAAIrD,OAAO,CAACsE,gBAAgB,CAAE,CAC5B,KAAMtE,QAAO,CAACsE,gBAAgB,CAAC/D,MAAM,CACvC,CACAA,MAAM,CAACK,GAAG,CAACT,QAAQ,CAAC,CAEpB,iEACAI,MAAM,CAACK,GAAG,CAAC,CAACC,GAAG,CAAEC,GAAG,CAAEC,IAAI,GAAK,CAC7BA,IAAI,CAAC,GAAAwD,gBAAQ,EAACC,cAAM,CAACC,SAAS,CAAEC,aAAK,CAACD,SAAS,CAAC,CAClD,CAAC,CAAC,CAEF,GAAIE,8BAA6B,CACjC,GAAI3E,OAAO,CAAC4E,oBAAoB,CAAE,CAChCD,6BAA6B,CAAG,KAAM3E,QAAO,CAAC4E,oBAAoB,CAACrE,MAAM,CAC3E,CAEA,oBACA,GAAI,CAACoE,6BAA6B,CAAE,CAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACApE,MAAM,CAACK,GAAG,CAAC,CAACiE,KAAK,CAAEhE,GAAG,CAAEC,GAAG,CAAEC,IAAI,GAAK,CACpC;AACA;AACA,GAAID,GAAG,CAACgE,WAAW,CAAE,MAAO/D,KAAI,CAAC8D,KAAK,CAAC,CAEvC,KAAME,OAAM,CAAGF,KAAK,CAACE,MAAM,EAAIL,aAAK,CAACM,qBAAqB,CAC1D,KAAMC,WAAU,CAAGF,MAAM,EAAIL,aAAK,CAACM,qBAAqB,CAExD;AACAhF,OAAO,CAACU,MAAM,CAACwE,GAAG,CAACD,UAAU,CAAG,OAAO,CAAG,OAAO,CAAEJ,KAAK,CAAC,CAEzD,GAAIM,QAAO,CAAGN,KAAK,CAACM,OAAO,EAAI,GAAAC,uBAAe,EAACL,MAAM,CAAC,CACtD,GAAIE,UAAU,EAAIpB,OAAO,CAACwB,GAAG,CAACC,QAAQ,GAAK,YAAY,CAAE,CACvDH,OAAO,CAAGX,cAAM,CAACQ,qBACnB,CAEAlE,GAAG,CAACiE,MAAM,CAACA,MAAM,CAAC,CAAC9C,IAAI,CAACkD,OAAO,CAAC,CAChC,MAAOI,UACT,CAAC,CACH,CAEA,MAAOhF,OACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["themed","COMPOSE","PRIORITY","NODE_CONFIG_ENV","process","env","NODE_ENV","JU","webpack","requireWeak","__dirname","withRetries","action","maxRetries","interval","n","error","timer"],"sources":["../../../../src/shared/utils/index.js"],"sourcesContent":["import themed, {\n COMPOSE,\n PRIORITY,\n ThemeProvider,\n} from '@dr.pogodin/react-themes';\n\nimport config from './config';\nimport * as isomorphy from './isomorphy';\nimport time, { timer } from './time';\nimport * as webpack from './webpack';\n\nexport * from './Barrier';\nexport { default as Emitter } from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport { default as splitComponent } from './splitComponent';\n\nthemed.COMPOSE = COMPOSE;\nthemed.PRIORITY = PRIORITY;\n\n// Note: it should be done this way, as in some environments\n// \"process\" might not exist, and process.env.NODE_CONFIG_ENV\n// not injected by Webpack.\nlet NODE_CONFIG_ENV;\ntry {\n NODE_CONFIG_ENV = process.env.NODE_CONFIG_ENV;\n} catch { /* noop */ }\n\nconst env = NODE_CONFIG_ENV || process.env.NODE_ENV;\nconst JU = env !== 'production' && webpack.requireWeak('./jest', __dirname);\n\n/**\n * @category Utilities\n * @global\n * @func withRetries\n * @desc\n * ```js\n * import { withRetries } from '@dr.pogodin/react-utils';\n * ```\n * Attempts to perform given asynchronous `action` up to `maxRetries` times,\n * with the given `interval` between attempts. If any attempt is successful,\n * the result is returned immediately, with no further attempts done;\n * otherwise, if all attempts fail, the result Promise rejects after the last\n * attempt.\n * @param {function} action\n * @param {number} [maxRetries=5] Optional. Maximum number of retries. Defaults\n * to 5 attempts.\n * @param {number} [interval=1000] Optional. Interval between retries [ms].\n * Defaults to 1 second.\n * @return {Promise} Resolves to the result of successful operation, or\n * rejects with the error from the latst failed attempt.\n * @example\n * import { withRetries } from '@dr.pogodin/react-utils';\n *\n * let firstCall = true;\n *\n * function sampleAction() {\n * if (!firstCall) return 'success';\n * firstCall = false;\n * throw Error('The first call to this method fails');\n * }\n *\n * withRetries(sampleAction).then(console.log);\n * // It will print 'success' after one second, once the second attempt\n * // is performed.\n */\nexport async function withRetries(action, maxRetries = 5, interval = 1000) {\n /* eslint-disable no-await-in-loop */\n for (let n = 1; ; ++n) {\n try {\n return await action();\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n /* eslint-enable no-await-in-loop */\n}\n\nexport {\n config,\n isomorphy,\n JU,\n themed,\n ThemeProvider,\n time,\n webpack,\n};\n"],"mappings":"0nCAAA,8EAMA,wDACA,8DAAyC,4BACzC,qDACA,0DAAqC,wBAErC,gVACA,0DACA,8DACA,wEAA6D,o9BAE7DA,oBAAM,CAACC,OAAO,CAAGA,oBAAO,CACxBD,oBAAM,CAACE,QAAQ,CAAGA,qBAAQ,CAE1B;AACA;AACA;AACA,GAAIC,gBAAe,CACnB,GAAI,CACFA,eAAe,CAAGC,OAAO,CAACC,GAAG,CAACF,eAChC,CAAE,KAAM,CAAE,
|
|
1
|
+
{"version":3,"file":"index.js","names":["themed","COMPOSE","PRIORITY","NODE_CONFIG_ENV","process","env","NODE_ENV","JU","webpack","requireWeak","__dirname","withRetries","action","maxRetries","interval","n","error","timer"],"sources":["../../../../src/shared/utils/index.js"],"sourcesContent":["import themed, {\n COMPOSE,\n PRIORITY,\n ThemeProvider,\n} from '@dr.pogodin/react-themes';\n\nimport config from './config';\nimport * as isomorphy from './isomorphy';\nimport time, { timer } from './time';\nimport * as webpack from './webpack';\n\nexport * from './Barrier';\nexport { default as Emitter } from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport { default as splitComponent } from './splitComponent';\n\nthemed.COMPOSE = COMPOSE;\nthemed.PRIORITY = PRIORITY;\n\n// Note: it should be done this way, as in some environments\n// \"process\" might not exist, and process.env.NODE_CONFIG_ENV\n// not injected by Webpack.\nlet NODE_CONFIG_ENV;\ntry {\n NODE_CONFIG_ENV = process.env.NODE_CONFIG_ENV;\n} catch { /* noop */ }\n\nconst env = NODE_CONFIG_ENV || process.env.NODE_ENV;\nconst JU = env !== 'production' && webpack.requireWeak('./jest', __dirname);\n\n/**\n * @category Utilities\n * @global\n * @func withRetries\n * @desc\n * ```js\n * import { withRetries } from '@dr.pogodin/react-utils';\n * ```\n * Attempts to perform given asynchronous `action` up to `maxRetries` times,\n * with the given `interval` between attempts. If any attempt is successful,\n * the result is returned immediately, with no further attempts done;\n * otherwise, if all attempts fail, the result Promise rejects after the last\n * attempt.\n * @param {function} action\n * @param {number} [maxRetries=5] Optional. Maximum number of retries. Defaults\n * to 5 attempts.\n * @param {number} [interval=1000] Optional. Interval between retries [ms].\n * Defaults to 1 second.\n * @return {Promise} Resolves to the result of successful operation, or\n * rejects with the error from the latst failed attempt.\n * @example\n * import { withRetries } from '@dr.pogodin/react-utils';\n *\n * let firstCall = true;\n *\n * function sampleAction() {\n * if (!firstCall) return 'success';\n * firstCall = false;\n * throw Error('The first call to this method fails');\n * }\n *\n * withRetries(sampleAction).then(console.log);\n * // It will print 'success' after one second, once the second attempt\n * // is performed.\n */\nexport async function withRetries(action, maxRetries = 5, interval = 1000) {\n /* eslint-disable no-await-in-loop */\n for (let n = 1; ; ++n) {\n try {\n return await action();\n } catch (error) {\n if (n < maxRetries) await timer(interval);\n else throw error;\n }\n }\n /* eslint-enable no-await-in-loop */\n}\n\nexport {\n config,\n isomorphy,\n JU,\n themed,\n ThemeProvider,\n time,\n webpack,\n};\n"],"mappings":"0nCAAA,8EAMA,wDACA,8DAAyC,4BACzC,qDACA,0DAAqC,wBAErC,gVACA,0DACA,8DACA,wEAA6D,o9BAE7DA,oBAAM,CAACC,OAAO,CAAGA,oBAAO,CACxBD,oBAAM,CAACE,QAAQ,CAAGA,qBAAQ,CAE1B;AACA;AACA;AACA,GAAIC,gBAAe,CACnB,GAAI,CACFA,eAAe,CAAGC,OAAO,CAACC,GAAG,CAACF,eAChC,CAAE,KAAM,CAAE,WAEV,KAAME,IAAG,CAAGF,eAAe,EAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,CACnD,KAAMC,GAAE,CAAGF,GAAG,GAAK,YAAY,EAAIG,OAAO,CAACC,WAAW,UAAWC,SAAS,CAAC,CAE3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAlCA,cAmCO,cAAeC,YAAW,CAACC,MAAM,CAAEC,UAAU,CAAG,CAAC,CAAEC,QAAQ,CAAG,IAAI,CAAE,CACzE,qCACA,IAAK,GAAIC,EAAC,CAAG,CAAC,EAAI,EAAEA,CAAC,CAAE,CACrB,GAAI,CACF,MAAO,MAAMH,OAAM,EACrB,CAAE,MAAOI,KAAK,CAAE,CACd,GAAID,CAAC,CAAGF,UAAU,CAAE,KAAM,GAAAI,WAAK,EAACH,QAAQ,CAAC,CAAC,IACrC,MAAME,MACb,CACF,CACA,oCACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;exports.timer=timer;exports.useCurrent=useCurrent;var _dayjs=_interopRequireDefault(require("dayjs"));var _lodash=require("lodash");var _react=require("react");var _reactGlobalState=require("@dr.pogodin/react-global-state");var _Barrier=require("./Barrier")
|
|
1
|
+
"use strict";var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;exports.timer=timer;exports.useCurrent=useCurrent;exports.useTimezoneOffset=useTimezoneOffset;var _cookie=_interopRequireDefault(require("cookie"));var _dayjs=_interopRequireDefault(require("dayjs"));var _lodash=require("lodash");var _react=require("react");var _reactGlobalState=require("@dr.pogodin/react-global-state");var _Barrier=require("./Barrier");/* global document */ /**
|
|
2
2
|
* @static
|
|
3
3
|
* @const SEC_MS
|
|
4
4
|
* @desc One second, expressed in milliseconds (equals 1000 ms).
|
|
@@ -67,5 +67,26 @@
|
|
|
67
67
|
* thus automatically re-rendering components dependent on this hook, or
|
|
68
68
|
* the global state with the period equal to the `precision`.
|
|
69
69
|
* @return {number} Unix timestamp in milliseconds.
|
|
70
|
-
*/function useCurrent({autorefresh=false,globalStatePath="currentTime",precision=5*_dayjs.default.SEC_MS}={}){const[now,setter]=(0,_reactGlobalState.useGlobalState)(globalStatePath,Date.now);(0,_react.useEffect)(()=>{let timerId;const update=()=>{setter(old=>{const neu=Date.now();return Math.abs(neu-old)>precision?neu:old});if(autorefresh)timerId=setTimeout(update,precision)};update();return()=>{if(timerId)clearTimeout(timerId)}},[autorefresh,precision,setter]);return now}
|
|
70
|
+
*/function useCurrent({autorefresh=false,globalStatePath="currentTime",precision=5*_dayjs.default.SEC_MS}={}){const[now,setter]=(0,_reactGlobalState.useGlobalState)(globalStatePath,Date.now);(0,_react.useEffect)(()=>{let timerId;const update=()=>{setter(old=>{const neu=Date.now();return Math.abs(neu-old)>precision?neu:old});if(autorefresh)timerId=setTimeout(update,precision)};update();return()=>{if(timerId)clearTimeout(timerId)}},[autorefresh,precision,setter]);return now}/**
|
|
71
|
+
* Returns client's timezone offset (the difference, in milliseconds, between
|
|
72
|
+
* a timestamp evaluated in the user's timezone, and the same moment of time
|
|
73
|
+
* represented as a standard timestamp in UTC timzone) in an SSR-friendly way,
|
|
74
|
+
* i.e. adding the result of this hook to a standard timestamp will shift it
|
|
75
|
+
* in such way that when formatted to a human-readable form it will represent
|
|
76
|
+
* the time in the user's timezone.
|
|
77
|
+
*
|
|
78
|
+
* Technically, on the first ever call at the server-side it returns zero,
|
|
79
|
+
* then at the client side it initially returns zero, then determines the actual
|
|
80
|
+
* timezone offset, returns it from the hook and also sets it as a cookie.
|
|
81
|
+
* Subsequent renders on the server side will use that cookie to report
|
|
82
|
+
* the user's timezone right away.
|
|
83
|
+
*
|
|
84
|
+
* @param {object} [options] Optional settings.
|
|
85
|
+
* @param {string} [options.cookieName="timezoneOffset"] Optional. The name of
|
|
86
|
+
* cookie to use to store the timezone offset. Defaults "timezoneOffset". Set
|
|
87
|
+
* to a falsy value to forbid using cookies altogether (in that case the hook
|
|
88
|
+
* will always return zero value at the server-side, and in the first render
|
|
89
|
+
* at the client-side).
|
|
90
|
+
* @return {number} Timezone offset.
|
|
91
|
+
*/function useTimezoneOffset({cookieName="timezoneOffset"}={}){const ssrContext=(0,_reactGlobalState.getSsrContext)(false);const[offset,setOffset]=(0,_react.useState)(()=>{const value=cookieName&&ssrContext?.req?.cookies?.[cookieName];return value?parseInt(value,10):0});(0,_react.useEffect)(()=>{const date=new Date;const value=-date.getTimezoneOffset()*_dayjs.default.MIN_MS;setOffset(value);if(cookieName){document.cookie=_cookie.default.serialize(cookieName,value,{path:"/"})}},[cookieName]);return offset}_dayjs.default.timer=timer;_dayjs.default.useCurrent=useCurrent;_dayjs.default.useTimezoneOffset=useTimezoneOffset;var _default=_dayjs.default;exports.default=_default;
|
|
71
92
|
//# sourceMappingURL=time.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","names":["dayjs","SEC_MS","MIN_MS","HOUR_MS","DAY_MS","YEAR_MS","now","Date","timer","timeout","res","Barrier","id","setTimeout","resolve","bind","abort","clearTimeout","noop","useCurrent","autorefresh","globalStatePath","precision","setter","useGlobalState","useEffect","timerId","update","old","neu","Math","abs"],"sources":["../../../../src/shared/utils/time.js"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"time.js","names":["dayjs","SEC_MS","MIN_MS","HOUR_MS","DAY_MS","YEAR_MS","now","Date","timer","timeout","res","Barrier","id","setTimeout","resolve","bind","abort","clearTimeout","noop","useCurrent","autorefresh","globalStatePath","precision","setter","useGlobalState","useEffect","timerId","update","old","neu","Math","abs","useTimezoneOffset","cookieName","ssrContext","getSsrContext","offset","setOffset","useState","value","req","cookies","parseInt","date","getTimezoneOffset","document","cookie","Cookie","serialize","path"],"sources":["../../../../src/shared/utils/time.js"],"sourcesContent":["/* global document */\n\nimport Cookie from 'cookie';\nimport dayjs from 'dayjs';\nimport { noop } from 'lodash';\nimport { useEffect, useState } from 'react';\n\nimport { getSsrContext, useGlobalState } from '@dr.pogodin/react-global-state';\n\nimport { Barrier } from './Barrier';\n\n/**\n * @static\n * @const SEC_MS\n * @desc One second, expressed in milliseconds (equals 1000 ms).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.SEC_MS); // Prints: 1000\n */\ndayjs.SEC_MS = 1000;\n\n/**\n * @static\n * @const MIN_MS\n * @desc One minute, expressed in milliseconds (equals 60 × `SEC_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.MIN_MS); // Prints: 60000\n */\ndayjs.MIN_MS = 60 * dayjs.SEC_MS;\n\n/**\n * @static\n * @const HOUR_MS\n * @desc One hour, expressed in milliseconds (equals 60 × `MIN_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.HOUR_MS); // Prints: 3600000\n */\ndayjs.HOUR_MS = 60 * dayjs.MIN_MS;\n\n/**\n * @static\n * @const DAY_MS\n * @desc One day, expressed in milliseconds (equals 24 × `HOUR_MS`).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.DAY_MS); // Prints: 86400000\n */\ndayjs.DAY_MS = 24 * dayjs.HOUR_MS;\n\n/**\n * @static\n * @const YEAR_MS\n * @desc One year, expressed in milliseconds (equals 365 × `DAY_MS`,\n * thus a normal, non-leap year).\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.YEAR_MS); // Prints: 31536000000\n */\ndayjs.YEAR_MS = 365 * dayjs.DAY_MS;\n\n/**\n * @static\n * @func now\n * @desc Returns Unix timestamp [ms] (thus, it is just an alias for `Date.now`).\n * @return {number}\n * @example\n * import { time } from '@dr.pogodin/react-utils';\n * console.log(time.now()); // Prints the current timestamp, e.g. 1618608761000.\n */\ndayjs.now = Date.now;\n\n/**\n * Creates a Promise, which resolves after the given timeout.\n * @param {number} timeout Timeout [ms].\n * @return {Barrier} Resolves after the timeout. It has additional\n * .abort() method attached, which cancels the pending timer resolution\n * (without resolving or rejecting the barrier).\n */\nexport async function timer(timeout) {\n const res = new Barrier();\n if (timeout > 0) {\n const id = setTimeout(res.resolve.bind(res), timeout);\n res.abort = () => clearTimeout(id);\n } else {\n res.abort = noop;\n res.resolve();\n }\n return res;\n}\n\n/**\n * This react hook wraps Date.now() function in a SSR friendly way,\n * ensuring that all calls to useCurrent() within the same render return\n * exactly the same time (which is retrieved from Date.now() first, and\n * then stored in the global state to be reused in all other calls), which\n * is also passed and used in the first client side render, and then updated\n * with a finite precision to avoid infinite re-rendering loops.\n * @param {object} [options] Optional settings.\n * @param {string} [options.globalStatePath=\"currentTime\"] Global state path\n * to keep the current time value.\n * @param {number} [options.precision= 5 * time.SEC_MS] Current time precision.\n * The hook won't update the current time stored in the global state unless it\n * is different from Date.now() result by this number (in milliseconds).\n * Default to 5 seconds.\n * @param {boolean} [options.autorefresh=false] Set `true` to automatically\n * refresh time stored in the global state with the given `precision` (and\n * thus automatically re-rendering components dependent on this hook, or\n * the global state with the period equal to the `precision`.\n * @return {number} Unix timestamp in milliseconds.\n */\nexport function useCurrent({\n autorefresh = false,\n globalStatePath = 'currentTime',\n precision = 5 * dayjs.SEC_MS,\n} = {}) {\n const [now, setter] = useGlobalState(globalStatePath, Date.now);\n useEffect(() => {\n let timerId;\n const update = () => {\n setter((old) => {\n const neu = Date.now();\n return Math.abs(neu - old) > precision ? neu : old;\n });\n if (autorefresh) timerId = setTimeout(update, precision);\n };\n update();\n return () => {\n if (timerId) clearTimeout(timerId);\n };\n }, [autorefresh, precision, setter]);\n return now;\n}\n\n/**\n * Returns client's timezone offset (the difference, in milliseconds, between\n * a timestamp evaluated in the user's timezone, and the same moment of time\n * represented as a standard timestamp in UTC timzone) in an SSR-friendly way,\n * i.e. adding the result of this hook to a standard timestamp will shift it\n * in such way that when formatted to a human-readable form it will represent\n * the time in the user's timezone.\n *\n * Technically, on the first ever call at the server-side it returns zero,\n * then at the client side it initially returns zero, then determines the actual\n * timezone offset, returns it from the hook and also sets it as a cookie.\n * Subsequent renders on the server side will use that cookie to report\n * the user's timezone right away.\n *\n * @param {object} [options] Optional settings.\n * @param {string} [options.cookieName=\"timezoneOffset\"] Optional. The name of\n * cookie to use to store the timezone offset. Defaults \"timezoneOffset\". Set\n * to a falsy value to forbid using cookies altogether (in that case the hook\n * will always return zero value at the server-side, and in the first render\n * at the client-side).\n * @return {number} Timezone offset.\n */\nexport function useTimezoneOffset({\n cookieName = 'timezoneOffset',\n} = {}) {\n const ssrContext = getSsrContext(false);\n const [offset, setOffset] = useState(() => {\n const value = cookieName && ssrContext?.req?.cookies?.[cookieName];\n return value ? parseInt(value, 10) : 0;\n });\n useEffect(() => {\n const date = new Date();\n const value = -date.getTimezoneOffset() * dayjs.MIN_MS;\n setOffset(value);\n if (cookieName) {\n document.cookie = Cookie.serialize(cookieName, value, { path: '/' });\n }\n }, [cookieName]);\n return offset;\n}\n\ndayjs.timer = timer;\ndayjs.useCurrent = useCurrent;\ndayjs.useTimezoneOffset = useTimezoneOffset;\n\nexport default dayjs;\n"],"mappings":"8QAEA,sDACA,oDACA,8BACA,4BAEA,gEAEA,kCATA,sBAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACAA,cAAK,CAACC,MAAM,CAAG,IAAI,CAEnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACAD,cAAK,CAACE,MAAM,CAAG,EAAE,CAAGF,cAAK,CAACC,MAAM,CAEhC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACAD,cAAK,CAACG,OAAO,CAAG,EAAE,CAAGH,cAAK,CAACE,MAAM,CAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACAF,cAAK,CAACI,MAAM,CAAG,EAAE,CAAGJ,cAAK,CAACG,OAAO,CAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACAH,cAAK,CAACK,OAAO,CAAG,GAAG,CAAGL,cAAK,CAACI,MAAM,CAElC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACAJ,cAAK,CAACM,GAAG,CAAGC,IAAI,CAACD,GAAG,CAEpB;AACA;AACA;AACA;AACA;AACA;AACA,GACO,cAAeE,MAAK,CAACC,OAAO,CAAE,CACnC,KAAMC,IAAG,CAAG,GAAIC,iBAAS,CACzB,GAAIF,OAAO,CAAG,CAAC,CAAE,CACf,KAAMG,GAAE,CAAGC,UAAU,CAACH,GAAG,CAACI,OAAO,CAACC,IAAI,CAACL,GAAG,CAAC,CAAED,OAAO,CAAC,CACrDC,GAAG,CAACM,KAAK,CAAG,IAAMC,YAAY,CAACL,EAAE,CACnC,CAAC,IAAM,CACLF,GAAG,CAACM,KAAK,CAAGE,YAAI,CAChBR,GAAG,CAACI,OAAO,EACb,CACA,MAAOJ,IACT,CAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACO,QAASS,WAAU,CAAC,CACzBC,WAAW,CAAG,KAAK,CACnBC,eAAe,CAAG,aAAa,CAC/BC,SAAS,CAAG,CAAC,CAAGtB,cAAK,CAACC,MACxB,CAAC,CAAG,CAAC,CAAC,CAAE,CACN,KAAM,CAACK,GAAG,CAAEiB,MAAM,CAAC,CAAG,GAAAC,gCAAc,EAACH,eAAe,CAAEd,IAAI,CAACD,GAAG,CAAC,CAC/D,GAAAmB,gBAAS,EAAC,IAAM,CACd,GAAIC,QAAO,CACX,KAAMC,OAAM,CAAG,IAAM,CACnBJ,MAAM,CAAEK,GAAG,EAAK,CACd,KAAMC,IAAG,CAAGtB,IAAI,CAACD,GAAG,EAAE,CACtB,MAAOwB,KAAI,CAACC,GAAG,CAACF,GAAG,CAAGD,GAAG,CAAC,CAAGN,SAAS,CAAGO,GAAG,CAAGD,GACjD,CAAC,CAAC,CACF,GAAIR,WAAW,CAAEM,OAAO,CAAGb,UAAU,CAACc,MAAM,CAAEL,SAAS,CACzD,CAAC,CACDK,MAAM,EAAE,CACR,MAAO,IAAM,CACX,GAAID,OAAO,CAAET,YAAY,CAACS,OAAO,CACnC,CACF,CAAC,CAAE,CAACN,WAAW,CAAEE,SAAS,CAAEC,MAAM,CAAC,CAAC,CACpC,MAAOjB,IACT,CAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GACO,QAAS0B,kBAAiB,CAAC,CAChCC,UAAU,CAAG,gBACf,CAAC,CAAG,CAAC,CAAC,CAAE,CACN,KAAMC,WAAU,CAAG,GAAAC,+BAAa,EAAC,KAAK,CAAC,CACvC,KAAM,CAACC,MAAM,CAAEC,SAAS,CAAC,CAAG,GAAAC,eAAQ,EAAC,IAAM,CACzC,KAAMC,MAAK,CAAGN,UAAU,EAAIC,UAAU,EAAEM,GAAG,EAAEC,OAAO,GAAGR,UAAU,CAAC,CAClE,MAAOM,MAAK,CAAGG,QAAQ,CAACH,KAAK,CAAE,EAAE,CAAC,CAAG,CACvC,CAAC,CAAC,CACF,GAAAd,gBAAS,EAAC,IAAM,CACd,KAAMkB,KAAI,CAAG,GAAIpC,KAAM,CACvB,KAAMgC,MAAK,CAAG,CAACI,IAAI,CAACC,iBAAiB,EAAE,CAAG5C,cAAK,CAACE,MAAM,CACtDmC,SAAS,CAACE,KAAK,CAAC,CAChB,GAAIN,UAAU,CAAE,CACdY,QAAQ,CAACC,MAAM,CAAGC,eAAM,CAACC,SAAS,CAACf,UAAU,CAAEM,KAAK,CAAE,CAAEU,IAAI,CAAE,GAAI,CAAC,CACrE,CACF,CAAC,CAAE,CAAChB,UAAU,CAAC,CAAC,CAChB,MAAOG,OACT,CAEApC,cAAK,CAACQ,KAAK,CAAGA,KAAK,CACnBR,cAAK,CAACmB,UAAU,CAAGA,UAAU,CAC7BnB,cAAK,CAACgC,iBAAiB,CAAGA,iBAAiB,CAAC,aAE7BhC,cAAK"}
|