Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

find-my-way

Package Overview
Dependencies
Maintainers
2
Versions
116
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

find-my-way - npm Package Compare versions

Comparing version
8.1.0
to
8.2.0
+34
.github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
commit-message:
# Prefix all commit messages with "chore: "
prefix: "chore"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/"
commit-message:
# Prefix all commit messages with "chore: "
prefix: "chore"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
# Production dependencies without breaking changes
dependencies:
dependency-type: "production"
update-types:
- "minor"
- "patch"
# Production dependencies with breaking changes
dependencies-major:
dependency-type: "production"
update-types:
- "major"
# Development dependencies
dev-dependencies:
dependency-type: "development"
const t = require('tap')
const test = t.test
const FindMyWay = require('..')
const proxyquire = require('proxyquire')
const HandlerStorage = require('../lib/handler-storage')
const Constrainer = require('../lib/constrainer')
const { safeDecodeURIComponent } = require('../lib/url-sanitizer')
const acceptVersionStrategy = require('../lib/strategies/accept-version')
const httpMethodStrategy = require('../lib/strategies/http-method')
test('FULL_PATH_REGEXP and OPTIONAL_PARAM_REGEXP should be considered safe', (t) => {
t.plan(1)
t.doesNotThrow(() => require('..'))
})
test('should throw an error for unsafe FULL_PATH_REGEXP', (t) => {
t.plan(1)
t.throws(() => proxyquire('..', {
'safe-regex2': () => false
}), new Error('the FULL_PATH_REGEXP is not safe, update this module'))
})
test('Should throw an error for unsafe OPTIONAL_PARAM_REGEXP', (t) => {
t.plan(1)
let callCount = 0
t.throws(() => proxyquire('..', {
'safe-regex2': () => {
return ++callCount < 2
}
}), new Error('the OPTIONAL_PARAM_REGEXP is not safe, update this module'))
})
test('double colon does not define parametric node', (t) => {
t.plan(2)
const findMyWay = FindMyWay()
findMyWay.on('GET', '/::id', () => {})
const route1 = findMyWay.findRoute('GET', '/::id')
t.strictSame(route1.params, [])
findMyWay.on('GET', '/:foo(\\d+)::bar', () => {})
const route2 = findMyWay.findRoute('GET', '/:foo(\\d+)::bar')
t.strictSame(route2.params, ['foo'])
})
test('case insensitive static routes', (t) => {
t.plan(3)
const findMyWay = FindMyWay({
caseSensitive: false
})
findMyWay.on('GET', '/foo', () => {})
findMyWay.on('GET', '/foo/bar', () => {})
findMyWay.on('GET', '/foo/bar/baz', () => {})
t.ok(findMyWay.findRoute('GET', '/FoO'))
t.ok(findMyWay.findRoute('GET', '/FOo/Bar'))
t.ok(findMyWay.findRoute('GET', '/fOo/Bar/bAZ'))
})
test('wildcard must be the last character in the route', (t) => {
t.plan(3)
const expectedError = new Error('Wildcard must be the last character in the route')
const findMyWay = FindMyWay()
findMyWay.on('GET', '*', () => {})
t.throws(() => findMyWay.findRoute('GET', '*1'), expectedError)
t.throws(() => findMyWay.findRoute('GET', '*/'), expectedError)
t.throws(() => findMyWay.findRoute('GET', '*?'), expectedError)
})
test('does not find the route if maxParamLength is exceeded', t => {
t.plan(2)
const findMyWay = FindMyWay({
maxParamLength: 2
})
findMyWay.on('GET', '/:id(\\d+)', () => {})
t.equal(findMyWay.find('GET', '/123'), null)
t.ok(findMyWay.find('GET', '/12'))
})
test('Should check if a regex is safe to use', (t) => {
t.plan(1)
const findMyWay = FindMyWay()
// we must pass a safe regex to register the route
// findRoute will still throws the expected assertion error if we try to access it with unsafe reggex
findMyWay.on('GET', '/test/:id(\\d+)', () => {})
const unSafeRegex = /(x+x+)+y/
t.throws(() => findMyWay.findRoute('GET', `/test/:id(${unSafeRegex.toString()})`), {
message: "The regex '(/(x+x+)+y/)' is not safe!"
})
})
test('Disable safe regex check', (t) => {
t.plan(1)
const findMyWay = FindMyWay({ allowUnsafeRegex: true })
const unSafeRegex = /(x+x+)+y/
findMyWay.on('GET', `/test2/:id(${unSafeRegex.toString()})`, () => {})
t.doesNotThrow(() => findMyWay.findRoute('GET', `/test2/:id(${unSafeRegex.toString()})`))
})
test('throws error if no strategy registered for constraint key', (t) => {
t.plan(2)
const constrainer = new Constrainer()
const error = new Error('No strategy registered for constraint key invalid-constraint')
t.throws(() => constrainer.newStoreForConstraint('invalid-constraint'), error)
t.throws(() => constrainer.validateConstraints({ 'invalid-constraint': 'foo' }), error)
})
test('throws error if pass an undefined constraint value', (t) => {
t.plan(1)
const constrainer = new Constrainer()
const error = new Error('Can\'t pass an undefined constraint value, must pass null or no key at all')
t.throws(() => constrainer.validateConstraints({ key: undefined }), error)
})
test('Constrainer.noteUsage', (t) => {
t.plan(3)
const constrainer = new Constrainer()
t.equal(constrainer.strategiesInUse.size, 0)
constrainer.noteUsage()
t.equal(constrainer.strategiesInUse.size, 0)
constrainer.noteUsage({ host: 'fastify.io' })
t.equal(constrainer.strategiesInUse.size, 1)
})
test('Cannot derive constraints without active strategies.', (t) => {
t.plan(1)
const constrainer = new Constrainer()
const before = constrainer.deriveSyncConstraints
constrainer._buildDeriveConstraints()
t.sameStrict(constrainer.deriveSyncConstraints, before)
})
test('getMatchingHandler should return null if not compiled', (t) => {
t.plan(1)
const handlerStorage = new HandlerStorage()
t.equal(handlerStorage.getMatchingHandler({ foo: 'bar' }), null)
})
test('safeDecodeURIComponent should replace %3x to null for every x that is not a valid lowchar', (t) => {
t.plan(1)
t.equal(safeDecodeURIComponent('Hello%3xWorld'), 'HellonullWorld')
})
test('SemVerStore version should be a string', (t) => {
t.plan(1)
const Storage = acceptVersionStrategy.storage
t.throws(() => new Storage().set(1), new TypeError('Version should be a string'))
})
test('SemVerStore.maxMajor should increase automatically', (t) => {
t.plan(3)
const Storage = acceptVersionStrategy.storage
const storage = new Storage()
t.equal(storage.maxMajor, 0)
storage.set('2')
t.equal(storage.maxMajor, 2)
storage.set('1')
t.equal(storage.maxMajor, 2)
})
test('SemVerStore.maxPatches should increase automatically', (t) => {
t.plan(3)
const Storage = acceptVersionStrategy.storage
const storage = new Storage()
storage.set('2.0.0')
t.sameStrict(storage.maxPatches, { '2.0': 0 })
storage.set('2.0.2')
t.sameStrict(storage.maxPatches, { '2.0': 2 })
storage.set('2.0.1')
t.sameStrict(storage.maxPatches, { '2.0': 2 })
})
test('Major version must be a numeric value', t => {
t.plan(1)
const findMyWay = FindMyWay()
t.throws(() => findMyWay.on('GET', '/test', { constraints: { version: 'x' } }, () => {}),
new TypeError('Major version must be a numeric value'))
})
test('httpMethodStrategy storage handles set and get operations correctly', (t) => {
t.plan(2)
const storage = httpMethodStrategy.storage()
t.equal(storage.get('foo'), null)
storage.set('foo', { bar: 'baz' })
t.strictSame(storage.get('foo'), { bar: 'baz' })
})
test('if buildPrettyMeta argument is undefined, will return an object', (t) => {
t.plan(1)
const findMyWay = FindMyWay()
t.sameStrict(findMyWay.buildPrettyMeta(), {})
})
+40
-6
name: Node CI
on: [push, pull_request]
on:
push:
branches:
- main
- next
pull_request:

@@ -15,13 +20,28 @@ permissions:

matrix:
node-version: [14.x, 16.x, 18.x, 20.x]
os: [ubuntu-latest, windows-latest, macOS-latest]
node-version:
- 14
- 16
- 18
- 20
- 21
- 22
os:
- ubuntu-latest
- windows-latest
- macOS-latest
exclude:
- os: windows-latest
node-version: 14.x
node-version: 14
- os: macos-latest
node-version: 14
- os: macos-latest
node-version: 16
- os: windows-latest
node-version: 22
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:

@@ -45,1 +65,15 @@ node-version: ${{ matrix.node-version }}

npm run test:typescript
automerge:
if: >
github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]'
needs: test
runs-on: ubuntu-latest
permissions:
actions: write
pull-requests: write
contents: write
steps:
- uses: fastify/github-action-merge-dependabot@9e7bfb249c69139d7bdcd8d984f9665edd49020b # v3.10.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
+27
-37

@@ -28,3 +28,3 @@ 'use strict'

const assert = require('assert')
const assert = require('node:assert')
const querystring = require('fast-querystring')

@@ -119,3 +119,3 @@ const isRegexSafe = require('safe-regex2')

const pathFull = path.replace(OPTIONAL_PARAM_REGEXP, '$1$2')
const pathOptional = path.replace(OPTIONAL_PARAM_REGEXP, '$2')
const pathOptional = path.replace(OPTIONAL_PARAM_REGEXP, '$2') || '/'

@@ -349,3 +349,2 @@ this.on(method, pathFull, opts, handler, store)

const isEndOfNode = charCode === 47 || j === pattern.length
if (isRegexParam || isStaticPart || isEndOfNode) {

@@ -413,5 +412,3 @@ const paramName = pattern.slice(lastParamStartIndex, j)

currentNode = currentNode.getWildcardChild()
if (currentNode === null) {
return null
}
parentNodePathIndex = i + 1

@@ -429,6 +426,2 @@

if (pattern === '*') {
pattern = '/*'
}
for (const existRoute of this.routes) {

@@ -444,3 +437,3 @@ const routeConstraints = existRoute.opts.constraints || {}

store: existRoute.store,
params: existRoute.params || []
params: existRoute.params
}

@@ -651,33 +644,32 @@ }

if (currentNode.kind === NODE_TYPES.PARAMETRIC) {
let paramEndIndex = originPath.indexOf('/', pathIndex)
if (paramEndIndex === -1) {
paramEndIndex = pathLen
}
// parametric node
let paramEndIndex = originPath.indexOf('/', pathIndex)
if (paramEndIndex === -1) {
paramEndIndex = pathLen
}
let param = originPath.slice(pathIndex, paramEndIndex)
if (shouldDecodeParam) {
param = safeDecodeURIComponent(param)
}
let param = originPath.slice(pathIndex, paramEndIndex)
if (shouldDecodeParam) {
param = safeDecodeURIComponent(param)
}
if (currentNode.isRegex) {
const matchedParameters = currentNode.regex.exec(param)
if (matchedParameters === null) continue
if (currentNode.isRegex) {
const matchedParameters = currentNode.regex.exec(param)
if (matchedParameters === null) continue
for (let i = 1; i < matchedParameters.length; i++) {
const matchedParam = matchedParameters[i]
if (matchedParam.length > maxParamLength) {
return null
}
params.push(matchedParam)
}
} else {
if (param.length > maxParamLength) {
for (let i = 1; i < matchedParameters.length; i++) {
const matchedParam = matchedParameters[i]
if (matchedParam.length > maxParamLength) {
return null
}
params.push(param)
params.push(matchedParam)
}
} else {
if (param.length > maxParamLength) {
return null
}
params.push(param)
}
pathIndex = paramEndIndex
}
pathIndex = paramEndIndex
}

@@ -752,4 +744,2 @@ }

if (Router.prototype[methodName]) throw new Error('Method already exists: ' + methodName)
Router.prototype[methodName] = function (path, handler, store) {

@@ -756,0 +746,0 @@ return this.on(m, path, handler, store)

@@ -5,3 +5,3 @@ 'use strict'

const acceptHostStrategy = require('./strategies/accept-host')
const assert = require('assert')
const assert = require('node:assert')

@@ -157,6 +157,4 @@ class Constrainer {

lines.push(' version: req.headers[\'accept-version\'],')
} else if (key === 'host') {
} else {
lines.push(' host: req.headers.host || req.headers[\':authority\'],')
} else {
throw new Error('unknown non-custom strategy for compiling constraint derivation function')
}

@@ -163,0 +161,0 @@ } else {

@@ -50,4 +50,4 @@ 'use strict'

const isMergedTree = constraintsNames.includes(httpMethodStrategy.name)
if (!isMergedTree && this.handlers.length >= 32) {
throw new Error('find-my-way supports a maximum of 32 route handlers per node when there are constraints, limit reached')
if (!isMergedTree && this.handlers.length >= 31) {
throw new Error('find-my-way supports a maximum of 31 route handlers per node when there are constraints, limit reached')
}

@@ -54,0 +54,0 @@

@@ -132,6 +132,3 @@ 'use strict'

getWildcardChild () {
if (this.wildcardChild) {
return this.wildcardChild
}
return null
return this.wildcardChild
}

@@ -138,0 +135,0 @@

'use strict'
const assert = require('assert')
const assert = require('node:assert')

@@ -4,0 +4,0 @@ function HostStorage () {

'use strict'
const assert = require('assert')
const assert = require('node:assert')

@@ -23,3 +23,7 @@ function SemVerStore () {

major = Number(major) || 0
if (isNaN(major)) {
throw new TypeError('Major version must be a numeric value')
}
major = Number(major)
minor = Number(minor) || 0

@@ -42,3 +46,3 @@ patch = Number(patch) || 0

if (patch >= (this.store[`${major}.${minor}`] || 0)) {
if (patch >= (this.maxPatches[`${major}.${minor}`] || 0)) {
this.maxPatches[`${major}.${minor}`] = patch

@@ -45,0 +49,0 @@ this.store[`${major}.${minor}.x`] = store

@@ -12,7 +12,4 @@ 'use strict'

},
deriveConstraint: (req) => {
/* istanbul ignore next */
return req.method
},
deriveConstraint: /* istanbul ignore next */ (req) => req.method,
mustMatchWhenDerived: true
}
{
"name": "find-my-way",
"version": "8.1.0",
"version": "8.2.0",
"description": "Crazy fast http radix based router",

@@ -43,2 +43,3 @@ "main": "index.js",

"pre-commit": "^1.2.2",
"proxyquire": "^2.1.3",
"rfdc": "^1.3.0",

@@ -54,3 +55,3 @@ "simple-git": "^3.7.1",

"fast-querystring": "^1.0.0",
"safe-regex2": "^2.0.0"
"safe-regex2": "^3.1.0"
},

@@ -57,0 +58,0 @@ "tsd": {

@@ -446,4 +446,4 @@ # find-my-way

```js
#### lookup(request, response, [context], [done])
Start a new search, `request` and `response` are the server req/res objects.<br>

@@ -450,0 +450,0 @@ If a route is found it will automatically call the handler, otherwise the default route will be called.<br>

@@ -6,2 +6,3 @@ 'use strict'

const FindMyWay = require('..')
const rfdc = require('rfdc')({ proto: true })

@@ -27,8 +28,11 @@ const customHeaderConstraint = {

test('should derive async constraint', t => {
test('should derive multiple async constraints', t => {
t.plan(2)
const router = FindMyWay({ constraints: { requestedBy: customHeaderConstraint } })
router.on('GET', '/', { constraints: { requestedBy: 'node' } }, () => 'asyncHandler')
const customHeaderConstraint2 = rfdc(customHeaderConstraint)
customHeaderConstraint2.name = 'requestedBy2'
const router = FindMyWay({ constraints: { requestedBy: customHeaderConstraint, requestedBy2: customHeaderConstraint2 } })
router.on('GET', '/', { constraints: { requestedBy: 'node', requestedBy2: 'node' } }, () => 'asyncHandler')
router.lookup(

@@ -35,0 +39,0 @@ {

@@ -77,1 +77,30 @@ 'use strict'

})
test('A route supports up to 31 host constraints', (t) => {
t.plan(1)
const findMyWay = FindMyWay()
for (let i = 0; i < 31; i++) {
const host = `h${i.toString().padStart(2, '0')}`
findMyWay.on('GET', '/', { constraints: { host } }, alpha)
}
t.equal(findMyWay.find('GET', '/', { host: 'h01' }).handler, alpha)
})
test('A route throws when constraint limit exceeded', (t) => {
t.plan(1)
const findMyWay = FindMyWay()
for (let i = 0; i < 31; i++) {
const host = `h${i.toString().padStart(2, '0')}`
findMyWay.on('GET', '/', { constraints: { host } }, alpha)
}
t.throws(
() => findMyWay.on('GET', '/', { constraints: { host: 'h31' } }, beta),
'find-my-way supports a maximum of 31 route handlers per node when there are constraints, limit reached'
)
})

@@ -198,1 +198,21 @@ 'use strict'

})
test('optional parameter on root', (t) => {
t.plan(2)
const findMyWay = FindMyWay({
defaultRoute: (req, res) => {
t.fail('Should not be defaultRoute')
}
})
findMyWay.on('GET', '/:optional?', (req, res, params) => {
if (params.optional) {
t.equal(params.optional, 'foo')
} else {
t.equal(params.optional, undefined)
}
})
findMyWay.lookup({ method: 'GET', url: '/', headers: {} }, null)
findMyWay.lookup({ method: 'GET', url: '/foo', headers: {} }, null)
})

Sorry, the diff of this file is not supported yet