10 Commits

Author SHA1 Message Date
AlecM33
26f2fc5165 exempt options calls from auth check 2025-12-29 15:55:26 -05:00
AlecM33
5bfe11e5a1 attempt to resolve options call issue 2025-12-29 15:30:56 -05:00
AlecM33
83dd5eb815 fix options call settings 2025-12-29 15:18:05 -05:00
AlecM33
054234b38d fix spacing 2025-12-29 15:10:49 -05:00
AlecM33
12568d31ea remove unused options 2025-12-29 15:10:14 -05:00
AlecM33
b749fa0801 handle options call 2025-12-29 15:09:37 -05:00
Alec
2ef27c8248 allow local admin dashboard (#212)
* allow local admin dashboard

* removed 'unused' constant...
2025-12-29 14:59:57 -05:00
Alec
75189d109a bigger role buttons, better delete icon, other small styling tweaks, update tutorial language (#211)
* bigger role buttons, other small styling tweaks, update tutorial language

* fix depracated github actions dependency

* fix margin
2025-12-28 23:38:18 -05:00
Alec
2a4fa2861f set content type for join errors (#207) 2025-02-07 13:53:30 -05:00
dependabot[bot]
4b4b005d8a Bump path-to-regexp and express (#206)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.12 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `path-to-regexp` from 0.1.10 to 0.1.12
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12)

Updates `express` from 4.21.1 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-06 17:43:05 -05:00
13 changed files with 78 additions and 54 deletions

View File

@@ -22,7 +22,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'npm' cache: 'npm'

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12V17" stroke="#e73333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 12V17" stroke="#e73333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 7H20" stroke="#e73333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 10V18C6 19.6569 7.34315 21 9 21H15C16.6569 21 18 19.6569 18 18V10" stroke="#e73333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 5C9 3.89543 9.89543 3 11 3H13C14.1046 3 15 3.89543 15 5V7H9V5Z" stroke="#e73333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 855 B

View File

@@ -369,7 +369,7 @@ export const HTMLFragments = {
<img tabindex="0" class="role-include" src="../images/add.svg" title="add one" alt="add one"/> <img tabindex="0" class="role-include" src="../images/add.svg" title="add one" alt="add one"/>
<img tabindex="0" class="role-info" src="../images/info.svg" title="info" alt="info"/> <img tabindex="0" class="role-info" src="../images/info.svg" title="info" alt="info"/>
<img tabindex="0" class="role-edit" src="../images/pencil.svg" title="edit" alt="edit"/> <img tabindex="0" class="role-edit" src="../images/pencil.svg" title="edit" alt="edit"/>
<img tabindex="0" class="role-remove" src="../images/delete.svg" title="remove" alt="remove"/> <img tabindex="0" class="role-remove" src="../images/delete-2.svg" title="remove" alt="remove"/>
</div>`, </div>`,
DECK_SELECT_ROLE_DEFAULT: DECK_SELECT_ROLE_DEFAULT:
`<div class="role-name"></div> `<div class="role-name"></div>

View File

@@ -454,9 +454,9 @@ input[type="number"] {
} }
#role-select { #role-select {
margin: 0.5em 1em 1.5em 0; margin: 0.5em 0;
overflow-y: auto; overflow-y: auto;
height: 20em; height: 22em;
} }
.default-role, .custom-role, .added-role { .default-role, .custom-role, .added-role {
@@ -492,8 +492,8 @@ input[type="number"] {
} }
#role-select img, #deck-status-container img { #role-select img, #deck-status-container img {
height: 20px; height: 25px;
margin: 0 8px; margin: 0 10px;
cursor: pointer; cursor: pointer;
padding: 5px; padding: 5px;
border-radius: 5px; border-radius: 5px;
@@ -505,7 +505,7 @@ input[type="number"] {
} }
#role-select img:nth-child(4) { #role-select img:nth-child(4) {
height: 18px; height: 25px;
} }
#role-select img:hover, #deck-status-container img:hover { #role-select img:hover, #deck-status-container img:hover {
@@ -683,7 +683,7 @@ input[type="number"] {
@media(max-width: 550px) { @media(max-width: 550px) {
#custom-roles-container, #deck-status-container { #custom-roles-container, #deck-status-container {
min-width: 85%; min-width: 90%;
} }
h1 { h1 {
font-size: 32px; font-size: 32px;

View File

@@ -182,7 +182,7 @@
} }
#timer-parameters { #timer-parameters {
width: 65px; width: fit-content;
} }
#role-edit-container-background, #timer-edit-container-background { #role-edit-container-background, #timer-edit-container-background {
@@ -268,6 +268,7 @@ h1 {
border-radius: 5px; border-radius: 5px;
padding: 7px; padding: 7px;
margin: 0.5em; margin: 0.5em;
text-align: center;
} }
#end-of-game-header button { #end-of-game-header button {

View File

@@ -21,7 +21,7 @@ button#home-create-button {
} }
.framed-phone-screenshot-container { .framed-phone-screenshot-container {
margin: 0 0 20px 0; margin: 0 0 0 0;
border: 1px solid #464552; border: 1px solid #464552;
} }
@@ -194,5 +194,6 @@ label[for="room-code"], label[for="player-name"] {
#about-container h2 { #about-container h2 {
font-size: 18px; font-size: 18px;
margin: 0 15px 20px 15px;
} }
} }

View File

@@ -45,16 +45,16 @@
</div> </div>
<div id="about-container"> <div id="about-container">
<div> <div>
<h2>Join a game and have a role dealt to your device.</h2>
<div class="framed-phone-screenshot-container"> <div class="framed-phone-screenshot-container">
<img id="framed-phone-screenshot" alt="framed phone screenshot" src="../images/framed-phone-screenshot_resized.webp"/> <img id="framed-phone-screenshot" alt="framed phone screenshot" src="../images/framed-phone-screenshot_resized.webp"/>
</div> </div>
<h2>Join a game and have a role dealt to your device.</h2>
</div> </div>
<div> <div>
<h2>Create your own game with default or custom roles.</h2>
<div class="framed-phone-screenshot-container"> <div class="framed-phone-screenshot-container">
<img id="framed-phone-screenshot-2" alt="framed phone screenshot" src="../images/framed-phone-screenshot-2_resized.webp"/> <img id="framed-phone-screenshot-2" alt="framed phone screenshot" src="../images/framed-phone-screenshot-2_resized.webp"/>
</div> </div>
<h2>Create your own game with default or custom roles.</h2>
</div> </div>
</div> </div>
<script src="/dist/home-bundle.js.gz"></script> <script src="/dist/home-bundle.js.gz"></script>

View File

@@ -37,10 +37,8 @@
</ul> </ul>
</div> </div>
<h1 class="how-to-use-header" id="purpose-of-the-app">Purpose</h1> <h1 class="how-to-use-header" id="purpose-of-the-app">Purpose</h1>
<div class="how-to-use-section">This app helps a group play Werewolf when meeting virtually, or when you don't have <div class="how-to-use-section">This app helps a group play Werewolf when meeting virtually, or when it's simply difficult to
Werewolf cards with you. In general, the app can be very efficient for setting up games of any size and configuration. play with physical cards. Set up games with any number of roles and deal them to everyone's device. It's flexible, free,
Once everyone has joined the room, cards can be quickly dealt and re-dealt, and important information such as
role descriptions, time remaining, and the status of players is conveniently centralized. It's flexible, free,
and doesn't require installing an app or creating an account. If you use this app, I'd love to hear about it. I and doesn't require installing an app or creating an account. If you use this app, I'd love to hear about it. I
am always looking for ways to improve this tool. am always looking for ways to improve this tool.
</div> </div>
@@ -50,27 +48,23 @@
<br> <br>
<h3>- Step One: Choosing a method of moderation</h3> <h3>- Step One: Choosing a method of moderation</h3>
<br> <br>
You have two options for moderation during the game. If the moderator isn't playing, you can choose the <span class="emphasized">Dedicated Choose either the <span class="emphasized">Dedicated
Moderator</span> option. Dedicated Moderators are not dealt into the game. Once they start the game, they will know Moderator</span> option or the <span class="emphasized">Temporary Moderator</span> option. Dedicated moderators
everyone's role. During the game, they can kill players, reveal players' roles, transfer their are not dealt into the game, while temporary moderators are. Both will have moderator powers, but temporary moderators
moderator powers, play/pause the timer (if there is one), end the game (revealing everyone's role), or return the game to the lobby. will not know anyone's role. When they first remove someone from the game, their moderator powers will be transferred to that person,
who will become a dedicated moderator.
<br><br> <br><br>
Similarly, you can also choose the <span class="emphasized">Temporary Moderator</span> option. You are dealt a role, Dedicated moderators can transfer their moderator powers to any player that has been eliminated,
and you have the same powers as the Dedicated Moderator, except game knowledge - you know the same or to a spectator. That way, if the current moderator has to leave, or simply does not want to moderate
information that a regular player does. When you remove the first player from the game (which can be yourself),
they will automatically become the dedicated moderator.
<br><br>
<span class="emphasized">Dedicated Moderators</span> can transfer their moderator powers to a player that is out,
or to a spectator. That way, if the current Dedicated Moderator has to leave, or simply does not want to moderate
anymore, they can easily delegate. anymore, they can easily delegate.
<br><br> <br><br>
<h3>- Step Two: Build your deck</h3> <h3>- Step Two: Build your deck</h3>
<br> <br>
There is a role box on this page that includes a list of <span class="emphasized">Default Roles</span> and a list There is a <span class="emphasized">Role Box</span> on this page that includes a list of <span class="emphasized">Default Roles</span> and a list
of <span class="emphasized">Custom Roles</span>, which can be displayed by selecting the appropriate button within the box. of <span class="emphasized">Custom Roles</span>, which can be displayed by selecting the appropriate button within the box.
If you want to add a certain role to the game, click the <span class="emphasized">green plus</span> and one copy If you want to add a certain role to the game, click the green plus, and one copy
of it will be added to the <span class="emphasized">Deck</span> which is the other box displaying a player count. of it will be added to the <span class="emphasized">Deck Box</span>, which displays the added roles and the corresponding player count.
Likewise, if you want to remove one copy of a given role, click the <span class="emphasized">red minus</span> on the role Likewise, if you want to remove one copy of a given role, click the red minus on the role
in the Deck Box. in the Deck Box.
<br><br> <br><br>
Here I add 3 villagers to the game, and then remove them: Here I add 3 villagers to the game, and then remove them:
@@ -95,13 +89,13 @@
<h3>- In the Lobby</h3> <h3>- In the Lobby</h3>
<br> <br>
In the Lobby, moderators can manage the people in the room and the cards in the game. By clicking In the Lobby, moderators can manage the people in the room and the cards in the game. By clicking
the <span class="emphasized">three vertical dots (AKA the "kebab menu")</span> next to a given player (<span class="emphasized">point A</span> the three vertical dots (AKA the "kebab menu") next to a given player (<span class="emphasized">point A</span>
in the screenshot below), you have the option to kick that player. You can do the same with a spectator by first in the screenshot below), you have the option to kick that player. You can do the same with a spectator by first
viewing the spectator list (<span class="emphasized">point C</span>) and clicking their kebab menus. By clicking the viewing the spectator list (<span class="emphasized">point C</span>) and clicking their kebab menus. By clicking the
"Edit Roles" button (<span class="emphasized">point B</span>), you can change which roles are in the game and the "Edit Roles" button (<span class="emphasized">point B</span>), you can change which roles are in the game and the
quantities of those roles. This button will bring up the same module you encountered when you first created the room. quantities of those roles. This button will bring up the same module you encountered when you first created the room.
Saving any changes to the roles may affect the player count. If you wish to <span class="emphasized">start the game (point B)</span>, the number Saving any changes to the roles may affect the player count. If you wish to start the game <span class="emphasized">(point B)</span>, the number
of Players in the Lobby must equal the number of cards in the game. of players in the lobby must equal the number of cards in the game.
<br><br> <br><br>
<img alt="moderator view in the lobby" class='tutorial-image-small-portrait' src="../images/tutorial/dedicated-mod-lobby-mobile.webp"/> <img alt="moderator view in the lobby" class='tutorial-image-small-portrait' src="../images/tutorial/dedicated-mod-lobby-mobile.webp"/>
<br><br> <br><br>
@@ -113,15 +107,15 @@
but not the "Reveal" option. Or, if you happen to have a role that reveals but is not immediately removed from the game, but not the "Reveal" option. Or, if you happen to have a role that reveals but is not immediately removed from the game,
you can use the "Reveal" option but not the "Kill" option. You of course don't have to utilize either of these options. you can use the "Reveal" option but not the "Kill" option. You of course don't have to utilize either of these options.
If you just want to use the app to deal cards, you are free to do that. The moderator also has permission to If you just want to use the app to deal cards, you are free to do that. The moderator also has permission to
play and pause the Timer (<span class="emphasized">Point B</span>), and can end the game (revealing everyone's role) play and pause the timer (<span class="emphasized">Point B</span>), and can end the game (revealing everyone's role)
or return the game to the Lobby (<span class="emphasized">Point C</span>), where it can be started anew with different settings. or return the game to the lobby (<span class="emphasized">Point C</span>), where it can be started again with different settings.
<br><br> <br><br>
<img alt="moderator view during the game" class='tutorial-image-small-portrait' src="../images/tutorial/dedicated-mod-in-progress-mobile.webp"/> <img alt="moderator view during the game" class='tutorial-image-small-portrait' src="../images/tutorial/dedicated-mod-in-progress-mobile.webp"/>
<br><br> <br><br>
Similarly, the <span class="emphasized">Temporary Moderator view</span> looks like the below image. They have Similarly, the <span class="emphasized">Temporary Moderator</span> view looks like the below image. They have
much the same abilities as a dedicated moderator, except they don't know role or alignment information and cannot much the same abilities as a dedicated moderator, except they don't know role or alignment information and cannot
transfer their powers. Their powers will be transferred automatically to the first person they remove from the game transfer their powers. Their powers will be transferred automatically to the first person they remove from the game
(which can be themselves). (which can be themselves!).
<br><br> <br><br>
<img alt="temporary moderator view during the game" class='tutorial-image-small-portrait' src="../images/tutorial/temp-mod-in-progress-mobile.webp"/> <img alt="temporary moderator view during the game" class='tutorial-image-small-portrait' src="../images/tutorial/temp-mod-in-progress-mobile.webp"/>
<br><br> <br><br>
@@ -136,7 +130,7 @@
<h1 class="how-to-use-header" id="being-a-player">Being a Player</h1> <h1 class="how-to-use-header" id="being-a-player">Being a Player</h1>
<div class="how-to-use-section"> <div class="how-to-use-section">
This is an example of what a <span class="emphasized">Player</span> is seeing, including the running timer, This is an example of what a <span class="emphasized">Player</span> is seeing, including the running timer,
their role card, and the player list. You can also edit your name for the Room by clicking the pencil next to it. their role card, and the player list. You can also edit your name for the room by clicking the pencil next to it.
Below, we flip our role card up and down by double-clicking it, and then we bring up the prompt to edit our name: Below, we flip our role card up and down by double-clicking it, and then we bring up the prompt to edit our name:
<br><br> <br><br>
<img alt='player-view' class='tutorial-image-small-portrait' src="../images/tutorial/player-view.gif"/> <img alt='player-view' class='tutorial-image-small-portrait' src="../images/tutorial/player-view.gif"/>
@@ -144,8 +138,8 @@
Players can view the timer, but only the current moderator can play and pause it. Your role card starts flipped over Players can view the timer, but only the current moderator can play and pause it. Your role card starts flipped over
- this is useful if you are in-person and don't want someone else accidentally seeing your role as - this is useful if you are in-person and don't want someone else accidentally seeing your role as
it is dealt. You can view your role at any time by double-clicking/double-tapping it. Requiring a double-click guards against the possibility it is dealt. You can view your role at any time by double-clicking/double-tapping it. Requiring a double-click guards against the possibility
of accidentally flipping your role when tapping other things. Within the Player List, you can see who is alive or of accidentally flipping your role when tapping other things. Within the player list, you can see who is alive or
dead and who has had their role revealed. There is also a <span class="emphasized">role info button</span> that, dead and who has had their role revealed. There is also a role info button that,
when pressed, displays all the different roles in the current game, including their descriptions and alignment (Good/Evil). when pressed, displays all the different roles in the current game, including their descriptions and alignment (Good/Evil).
<br><br> <br><br>
</div> </div>

24
package-lock.json generated
View File

@@ -13,7 +13,7 @@
"body-parser": "^1.20.3", "body-parser": "^1.20.3",
"compression-webpack-plugin": "^10.0.0", "compression-webpack-plugin": "^10.0.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.21.1", "express": "^4.21.2",
"express-force-https": "^1.0.0", "express-force-https": "^1.0.0",
"express-rate-limit": "^6.0.1", "express-rate-limit": "^6.0.1",
"open": "^7.0.3", "open": "^7.0.3",
@@ -47,7 +47,7 @@
"webpack-remove-debug": "^0.1.0" "webpack-remove-debug": "^0.1.0"
}, },
"engines": { "engines": {
"node": ">= 14.0.0" "node": ">= 20.0.0"
} }
}, },
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {
@@ -3934,9 +3934,10 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.21.1", "version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"license": "MIT",
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
@@ -3957,7 +3958,7 @@
"methods": "~1.1.2", "methods": "~1.1.2",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "0.1.10", "path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "6.13.0", "qs": "6.13.0",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
@@ -3972,6 +3973,10 @@
}, },
"engines": { "engines": {
"node": ">= 0.10.0" "node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
} }
}, },
"node_modules/express-force-https": { "node_modules/express-force-https": {
@@ -5857,9 +5862,10 @@
"dev": true "dev": true
}, },
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "0.1.10", "version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
}, },
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",

View File

@@ -30,7 +30,7 @@
"body-parser": "^1.20.3", "body-parser": "^1.20.3",
"compression-webpack-plugin": "^10.0.0", "compression-webpack-plugin": "^10.0.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.21.1", "express": "^4.21.2",
"express-force-https": "^1.0.0", "express-force-https": "^1.0.0",
"express-rate-limit": "^6.0.1", "express-rate-limit": "^6.0.1",
"open": "^7.0.3", "open": "^7.0.3",

View File

@@ -4,9 +4,21 @@ const debugMode = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())
const logger = require('../modules/Logger')(debugMode); const logger = require('../modules/Logger')(debugMode);
const eventManager = (require('../modules/singletons/EventManager.js')).instance; const eventManager = (require('../modules/singletons/EventManager.js')).instance;
const cors = require('cors'); const cors = require('cors');
const { CORS_OPTIONS, CONTENT_TYPE_VALIDATOR } = require('../config/globals'); const { CONTENT_TYPE_VALIDATOR } = require('../config/globals');
router.use(cors(CORS_OPTIONS)); const ADMIN_CORS_OPTIONS = (process.env.NODE_ENV?.trim() === 'development'
? {
origin: '*',
optionsSuccessStatus: 200
}
: {
origin: 'http://localhost:3000',
optionsSuccessStatus: 200
});
router.use(cors(ADMIN_CORS_OPTIONS));
router.options('/games/state', cors(ADMIN_CORS_OPTIONS), (req, res) => {
res.sendStatus(200);
});
router.post('/sockets/broadcast', (req, res, next) => { router.post('/sockets/broadcast', (req, res, next) => {
CONTENT_TYPE_VALIDATOR(req, res, next); CONTENT_TYPE_VALIDATOR(req, res, next);

View File

@@ -83,9 +83,11 @@ router.patch('/:code/players', async function (req, res) {
res.status(200).send({ cookie: data, environment: gameManager.environment }); res.status(200).send({ cookie: data, environment: gameManager.environment });
}).catch((data) => { }).catch((data) => {
console.error(data); console.error(data);
res.set('content-type', 'text/plain');
res.status(data.status || 500).send(data.reason); res.status(data.status || 500).send(data.reason);
}); });
} else { } else {
res.set('content-type', 'text/plain');
res.status(404).send(); res.status(404).send();
} }
} }

View File

@@ -162,7 +162,7 @@ const ServerBootstrapper = {
}; };
function isAuthorized (req) { function isAuthorized (req) {
if (process.env.NODE_ENV.trim() === 'development') { if (process.env.NODE_ENV.trim() === 'development' || req.method === 'OPTIONS') {
return true; return true;
} }