Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.
This commit is contained in:
21
node_modules/deterministic-object-hash/LICENSE
generated
vendored
Normal file
21
node_modules/deterministic-object-hash/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Zane Bauman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
120
node_modules/deterministic-object-hash/README.md
generated
vendored
Normal file
120
node_modules/deterministic-object-hash/README.md
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
# Deterministic-Object-Hash
|
||||
A deterministic object hashing algorithm for Node.js and web platform.
|
||||
|
||||
## The Problem
|
||||
Using `JSON.stringify` on two objects that are deeply equal does not lead to the same output string. Instead the keys are ordered in the same order that they were added. This leads to two objects that are deeply equal being hashed to different values.
|
||||
|
||||
```typescript
|
||||
import { createHash } from "crypto";
|
||||
import { isEqual } from "lodash";
|
||||
|
||||
const obj1: Record<string, string> = {};
|
||||
obj1['a'] = 'x';
|
||||
obj1['b'] = 'y';
|
||||
obj1['c'] = 'z';
|
||||
|
||||
const obj2: Record<string, string> = {};
|
||||
obj2['c'] = 'z';
|
||||
obj2['b'] = 'y';
|
||||
obj2['a'] = 'x';
|
||||
|
||||
isEqual(obj1, obj2);
|
||||
// -> true
|
||||
|
||||
const string1 = JSON.stringify(obj1);
|
||||
// -> {"a":"x","b":"y","c":"z"}
|
||||
const string2 = JSON.stringify(obj2);
|
||||
// -> {"c":"z","b":"y","a":"x"}
|
||||
|
||||
createHash('sha1').update(string1).digest('hex');
|
||||
// -> ff75fe071d236ce309c15d5636ecaa86c0519ebc
|
||||
createHash('sha1').update(string2).digest('hex');
|
||||
// -> 2e53bac865f7be77c8e10cd86d737fbbf259ed37
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
Pass a value and receive a deterministic hash of the value.
|
||||
|
||||
```typescript
|
||||
import deterministicHash from 'deterministic-object-hash';
|
||||
|
||||
const objA = { a: 'x', arr: [1,2,3,4], b: 'y' };
|
||||
const objB = { b: 'y', a: 'x', arr: [1,2,3,4] };
|
||||
|
||||
await deterministicHash({
|
||||
c: [ objA, objB ],
|
||||
b: objA,
|
||||
e: objB,
|
||||
f: ()=>{ Math.random(); },
|
||||
g: Symbol('Unique identity'),
|
||||
h: new Error('AHHH')
|
||||
});
|
||||
// -> 4c57bcb76498dca7b98ef9747c8f1e7f10c30388
|
||||
|
||||
await deterministicHash({
|
||||
h: new Error('AHHH'),
|
||||
e: objB,
|
||||
g: Symbol('Unique identity'),
|
||||
b: objA,
|
||||
f: ()=>{ Math.random(); },
|
||||
c: [ objA, objB ]
|
||||
});
|
||||
// -> 4c57bcb76498dca7b98ef9747c8f1e7f10c30388
|
||||
```
|
||||
|
||||
## Settings
|
||||
|
||||
A hash algorithm can be passed as the second argument. This takes any value that is valid for `webcrypto.subtle.digest`. The default is `SHA-1`. \
|
||||
A digest format can be passed as the third argument. This takes any value that is valid for `Hash.digest`. The default is `hex`.
|
||||
|
||||
|
||||
```typescript
|
||||
await deterministicHash('value', 'SHA-1');
|
||||
// -> efede6000ad4e1ff258a38866c71aa351d3c01f6
|
||||
await deterministicHash('value', 'SHA-256', 'hex');
|
||||
// -> a0b7821a11db531982044ca5ca2e788e2d749d6b696cd3aa4172342f584f2ee1
|
||||
await deterministicHash('value', 'SHA-512', 'base64');
|
||||
// -> 514CuHw/31qqUH2waqaqhKSMvLYH/YdZeRI4QqDBwhKbUk0/3mxhv4NUubXIl5Dm2k0VpU6ZZkmunEb10RngfQ==
|
||||
```
|
||||
|
||||
## Supported Values
|
||||
| | |
|
||||
| ------------------- | ----------------- |
|
||||
| String | Number |
|
||||
| Boolean | Function |
|
||||
| Plain Objects | Symbol |
|
||||
| undefined | null |
|
||||
| Infinity | NaN |
|
||||
| BigInt | Array |
|
||||
| Classes/Inheritance | Errors |
|
||||
| Date | RegExp |
|
||||
| Map | Set |
|
||||
| Int8Array | Uint8Array |
|
||||
| Int16Array | Uint16Array |
|
||||
| Int32Array | Uint32Array |
|
||||
| Float32Array | Float64Array |
|
||||
| BigInt64Array | BigUint64Array |
|
||||
| Uint8ClampedArray | globalThis |
|
||||
| ArrayBuffer | SharedArrayBuffer |
|
||||
|
||||
## Unsupported Values
|
||||
| | |
|
||||
| -------- | -------- |
|
||||
| WeakMap | WeakSet |
|
||||
| Atomics | DataView |
|
||||
| Promises | Reflect |
|
||||
| Proxy | |
|
||||
|
||||
Due to their nature, [WeakSet](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet#description) and [WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap#why_weakmap) are not enumerable. As a result there is no way to know what is in a WeakSet/WeakMap unless we are told.
|
||||
|
||||
## Support
|
||||
Currently this has only been tested on Node.js `18.x.x`. More tests are to come and this section will be updated as I test them.
|
||||
|
||||
## Contributors
|
||||
Contributions are welcome. Feel free to create a PR and tag [zbauman3](https://github.com/zbauman3).
|
||||
|
||||
### Past contributors:
|
||||
|
||||
- [zbauman3](https://github.com/zbauman3)
|
||||
- [RodrigoTomeES](https://github.com/RodrigoTomeES)
|
6
node_modules/deterministic-object-hash/dist/encoders.d.ts
generated
vendored
Normal file
6
node_modules/deterministic-object-hash/dist/encoders.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export declare const encoders: {
|
||||
base64: (input: ArrayBuffer) => string;
|
||||
base64url: (input: ArrayBuffer) => string;
|
||||
hex: (input: ArrayBuffer) => string;
|
||||
binary: (input: ArrayBuffer) => string;
|
||||
};
|
28
node_modules/deterministic-object-hash/dist/encoders.js
generated
vendored
Normal file
28
node_modules/deterministic-object-hash/dist/encoders.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.encoders = void 0;
|
||||
const base_64_1 = require("base-64");
|
||||
const binary = (input) => {
|
||||
let binary = "";
|
||||
const bytes = new Uint8Array(input);
|
||||
const len = bytes.byteLength;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const buffer = bytes[i];
|
||||
if (buffer)
|
||||
binary += String.fromCharCode(buffer);
|
||||
}
|
||||
return binary;
|
||||
};
|
||||
const hex = (input) => [...new Uint8Array(input)]
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
// @see https://stackoverflow.com/questions/35155089/node-sha-256-base64-digest
|
||||
// @see https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
|
||||
const base64 = (input) => (0, base_64_1.encode)(binary(input));
|
||||
const base64url = (input) => base64(input).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||
exports.encoders = {
|
||||
base64,
|
||||
base64url,
|
||||
hex,
|
||||
binary,
|
||||
};
|
5
node_modules/deterministic-object-hash/dist/index.d.ts
generated
vendored
Normal file
5
node_modules/deterministic-object-hash/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/// <reference types="node" />
|
||||
import { BinaryToTextEncoding, webcrypto } from "node:crypto";
|
||||
/** Creates a deterministic hash for all inputs. */
|
||||
export default function deterministicHash(input: unknown, algorithm?: Parameters<typeof webcrypto.subtle.digest>[0], output?: BinaryToTextEncoding): Promise<string>;
|
||||
export declare function deterministicString(input: unknown): string;
|
166
node_modules/deterministic-object-hash/dist/index.js
generated
vendored
Normal file
166
node_modules/deterministic-object-hash/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.deterministicString = void 0;
|
||||
const node_crypto_1 = require("node:crypto");
|
||||
const isPlainObject_1 = __importDefault(require("./isPlainObject"));
|
||||
const encoders_1 = require("./encoders");
|
||||
/** Creates a deterministic hash for all inputs. */
|
||||
async function deterministicHash(input, algorithm = "SHA-1", output = "hex") {
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode(deterministicString(input));
|
||||
const hash = await node_crypto_1.webcrypto.subtle.digest(algorithm, data);
|
||||
return encoders_1.encoders[output](hash);
|
||||
}
|
||||
exports.default = deterministicHash;
|
||||
function deterministicString(input) {
|
||||
if (typeof input === 'string') {
|
||||
//wrap in quotes (and escape queotes) to differentiate from stringified primitives
|
||||
return JSON.stringify(input);
|
||||
}
|
||||
else if (typeof input === 'symbol' || typeof input === 'function') {
|
||||
//use `toString` for an accurate representation of these
|
||||
return input.toString();
|
||||
}
|
||||
else if (typeof input === 'bigint') {
|
||||
//bigint turns into a string int, so I need to differentiate it from a normal int
|
||||
return `${input}n`;
|
||||
}
|
||||
else if (input === globalThis || input === undefined || input === null || typeof input === 'boolean' || typeof input === 'number' || typeof input !== 'object') {
|
||||
//cast to string for any of these
|
||||
return `${input}`;
|
||||
}
|
||||
else if (input instanceof Date) {
|
||||
//using timestamp for dates
|
||||
return `(${input.constructor.name}:${input.getTime()})`;
|
||||
}
|
||||
else if (input instanceof RegExp || input instanceof Error || input instanceof WeakMap || input instanceof WeakSet) {
|
||||
//use simple `toString`. `WeakMap` and `WeakSet` are non-iterable, so this is the best I can do
|
||||
return `(${input.constructor.name}:${input.toString()})`;
|
||||
}
|
||||
else if (input instanceof Set) {
|
||||
//add the constructor as a key
|
||||
let ret = `(${input.constructor.name}:[`;
|
||||
//add all unique values
|
||||
for (const val of input.values()) {
|
||||
ret += `${deterministicString(val)},`;
|
||||
}
|
||||
ret += '])';
|
||||
return ret;
|
||||
}
|
||||
else if (Array.isArray(input) ||
|
||||
input instanceof Int8Array ||
|
||||
input instanceof Uint8Array ||
|
||||
input instanceof Uint8ClampedArray ||
|
||||
input instanceof Int16Array ||
|
||||
input instanceof Uint16Array ||
|
||||
input instanceof Int32Array ||
|
||||
input instanceof Uint32Array ||
|
||||
input instanceof Float32Array ||
|
||||
input instanceof Float64Array ||
|
||||
input instanceof BigInt64Array ||
|
||||
input instanceof BigUint64Array) {
|
||||
//add the constructor as a key
|
||||
let ret = `(${input.constructor.name}:[`;
|
||||
//add all key/value pairs
|
||||
for (const [k, v] of input.entries()) {
|
||||
ret += `(${k}:${deterministicString(v)}),`;
|
||||
}
|
||||
ret += '])';
|
||||
return ret;
|
||||
}
|
||||
else if (input instanceof ArrayBuffer || input instanceof SharedArrayBuffer) {
|
||||
//each typed array must be in multiples of their byte size.
|
||||
//see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#typedarray_objects
|
||||
if (input.byteLength % 8 === 0) {
|
||||
return deterministicString(new BigUint64Array(input));
|
||||
}
|
||||
else if (input.byteLength % 4 === 0) {
|
||||
return deterministicString(new Uint32Array(input));
|
||||
}
|
||||
else if (input.byteLength % 2 === 0) {
|
||||
return deterministicString(new Uint16Array(input));
|
||||
}
|
||||
else {
|
||||
/** @todo - Change this to a system that breaks it down into parts. E.g. byteLength of 17 = BigUint64Array*2 and Uint8Array */
|
||||
let ret = '(';
|
||||
for (let i = 0; i < input.byteLength; i++) {
|
||||
ret += `${deterministicString(new Uint8Array(input.slice(i, i + 1)))},`;
|
||||
}
|
||||
ret += ')';
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (input instanceof Map || (0, isPlainObject_1.default)(input)) {
|
||||
//all key/values will be put here for sorting by key
|
||||
const sortable = [];
|
||||
//get key/value pairs
|
||||
const entries = (input instanceof Map
|
||||
? input.entries()
|
||||
: Object.entries(input));
|
||||
//add all key value pairs
|
||||
for (const [k, v] of entries) {
|
||||
sortable.push([deterministicString(k), deterministicString(v)]);
|
||||
}
|
||||
//if not a map, get Symbol keys and add them
|
||||
if (!(input instanceof Map)) {
|
||||
const symbolKeys = Object.getOwnPropertySymbols(input);
|
||||
//convert each symbol key to a key/value pair
|
||||
for (let i = 0; i < symbolKeys.length; i++) {
|
||||
sortable.push([
|
||||
deterministicString(symbolKeys[i]),
|
||||
deterministicString(
|
||||
//have to ignore because `noImplicitAny` is `true` but this is implicitly `any`
|
||||
//@ts-ignore
|
||||
input[symbolKeys[i]])
|
||||
]);
|
||||
}
|
||||
}
|
||||
//sort alphabetically by keys
|
||||
sortable.sort(([a], [b]) => a.localeCompare(b));
|
||||
//add the constructor as a key
|
||||
let ret = `(${input.constructor.name}:[`;
|
||||
//add all of the key/value pairs
|
||||
for (const [k, v] of sortable) {
|
||||
ret += `(${k}:${v}),`;
|
||||
}
|
||||
ret += '])';
|
||||
return ret;
|
||||
}
|
||||
//a class/non-plain object
|
||||
const allEntries = [];
|
||||
for (const k in input) {
|
||||
allEntries.push([
|
||||
deterministicString(k),
|
||||
deterministicString(
|
||||
//have to ignore because `noImplicitAny` is `true` but this is implicitly `any`
|
||||
//@ts-ignore
|
||||
input[k])
|
||||
]);
|
||||
}
|
||||
//get all own property symbols
|
||||
const symbolKeys = Object.getOwnPropertySymbols(input);
|
||||
//convert each symbol key to a key/value pair
|
||||
for (let i = 0; i < symbolKeys.length; i++) {
|
||||
allEntries.push([
|
||||
deterministicString(symbolKeys[i]),
|
||||
deterministicString(
|
||||
//have to ignore because `noImplicitAny` is `true` but this is implicitly `any`
|
||||
//@ts-ignore
|
||||
input[symbolKeys[i]])
|
||||
]);
|
||||
}
|
||||
//sort alphabetically by keys
|
||||
allEntries.sort(([a], [b]) => a.localeCompare(b));
|
||||
//add the constructor as a key
|
||||
let ret = `(${input.constructor.name}:[`;
|
||||
//add all of the key/value pairs
|
||||
for (const [k, v] of allEntries) {
|
||||
ret += `(${k}:${v}),`;
|
||||
}
|
||||
ret += '])';
|
||||
return ret;
|
||||
}
|
||||
exports.deterministicString = deterministicString;
|
1
node_modules/deterministic-object-hash/dist/isPlainObject.d.ts
generated
vendored
Normal file
1
node_modules/deterministic-object-hash/dist/isPlainObject.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export default function isPlainObject(value: unknown): boolean;
|
27
node_modules/deterministic-object-hash/dist/isPlainObject.js
generated
vendored
Normal file
27
node_modules/deterministic-object-hash/dist/isPlainObject.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const objConstructorString = Function.prototype.toString.call(Object);
|
||||
function isPlainObject(value) {
|
||||
//base object
|
||||
if (typeof value !== 'object' ||
|
||||
value === null ||
|
||||
Object.prototype.toString.call(value) !== '[object Object]') {
|
||||
return false;
|
||||
}
|
||||
//get the prototype
|
||||
const proto = Object.getPrototypeOf(value);
|
||||
//no prototype === all good
|
||||
if (proto === null) {
|
||||
return true;
|
||||
}
|
||||
//has own prop 'constructor'
|
||||
if (!Object.prototype.hasOwnProperty.call(proto, 'constructor')) {
|
||||
return false;
|
||||
}
|
||||
// validate that the constructor is `Object`
|
||||
return (typeof proto.constructor === 'function' &&
|
||||
proto.constructor instanceof proto.constructor &&
|
||||
Function.prototype.toString.call(proto.constructor) === objConstructorString);
|
||||
}
|
||||
exports.default = isPlainObject;
|
||||
;
|
42
node_modules/deterministic-object-hash/package.json
generated
vendored
Normal file
42
node_modules/deterministic-object-hash/package.json
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "deterministic-object-hash",
|
||||
"version": "2.0.2",
|
||||
"description": "A deterministic object hashing algorithm for Node.js.",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"test": "npx jest",
|
||||
"build": "npx tsc -b ./",
|
||||
"ts-watch": "npx tsc -b --watch ./"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zbauman3/Deterministic-Object-Hash.git"
|
||||
},
|
||||
"keywords": [
|
||||
"deterministic",
|
||||
"object",
|
||||
"hash",
|
||||
"algorithm"
|
||||
],
|
||||
"author": "Zane Bauman",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/zbauman3/Deterministic-Object-Hash/issues"
|
||||
},
|
||||
"homepage": "https://github.com/zbauman3/Deterministic-Object-Hash#readme",
|
||||
"devDependencies": {
|
||||
"@types/base-64": "^1.0.2",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/lodash": "^4.14.178",
|
||||
"@types/node": "18.18.9",
|
||||
"jest": "^27.4.7",
|
||||
"lodash": "^4.17.21",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"base-64": "^1.0.0"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user