Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
54a2880391 | |||
b7aeee4706 | |||
b3eab0d6c9 | |||
ad4194a981 | |||
e1f22a01a6 | |||
91c0858d9f | |||
8094b6507f | |||
e40f410830 | |||
c1043e65e2 | |||
67d9928a61 | |||
e6636d373b | |||
811d797e1b | |||
0909c4f648 |
10
.github/workflows/build.yaml
vendored
10
.github/workflows/build.yaml
vendored
@ -48,3 +48,13 @@ jobs:
|
|||||||
uses: ztimson/actions/tag@develop
|
uses: ztimson/actions/tag@develop
|
||||||
with:
|
with:
|
||||||
tag: ${{env.VERSION}}
|
tag: ${{env.VERSION}}
|
||||||
|
|
||||||
|
|
||||||
|
docs:
|
||||||
|
name: Publish Documentation
|
||||||
|
needs: build
|
||||||
|
uses: ztimson/actions/.github/workflows/docker.yaml@develop
|
||||||
|
with:
|
||||||
|
name: ztimson/utils
|
||||||
|
repository: ${{github.server_url}}/${{github.repository}}.git
|
||||||
|
pass: ${{secrets.DEPLOY_TOKEN}}
|
||||||
|
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Build application
|
||||||
|
FROM node:alpine as build
|
||||||
|
|
||||||
|
RUN mkdir /app
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN if [ ! -d "node_modules" ]; then npm i; fi && \
|
||||||
|
if [ ! -d "dist" ]; then npm run docs; fi
|
||||||
|
|
||||||
|
# Use Nginx to serve
|
||||||
|
FROM nginx:1.23-alpine
|
||||||
|
|
||||||
|
COPY --from=build /app/docs /usr/share/nginx/html
|
@ -20,7 +20,7 @@ Javascript/Typescript Utilities
|
|||||||
|
|
||||||
---
|
---
|
||||||
<div>
|
<div>
|
||||||
<a href="https://git.zakscode.com/ztimson/utils/wiki" target="_blank">Documentation</a>
|
<a href="https://utils.docs.zakscode.com" target="_blank">Documentation</a>
|
||||||
• <a href="https://git.zakscode.com/ztimson/utils/releases" target="_blank">Release Notes</a>
|
• <a href="https://git.zakscode.com/ztimson/utils/releases" target="_blank">Release Notes</a>
|
||||||
• <a href="https://git.zakscode.com/ztimson/utils/issues/new?template=.github%2fissue_template%2fbug.md" target="_blank">Report a Bug</a>
|
• <a href="https://git.zakscode.com/ztimson/utils/issues/new?template=.github%2fissue_template%2fbug.md" target="_blank">Report a Bug</a>
|
||||||
• <a href="https://git.zakscode.com/ztimson/utils/issues/new?template=.github%2fissue_template%2fenhancement.md" target="_blank">Request a Feature</a>
|
• <a href="https://git.zakscode.com/ztimson/utils/issues/new?template=.github%2fissue_template%2fenhancement.md" target="_blank">Request a Feature</a>
|
||||||
@ -36,7 +36,7 @@ Javascript/Typescript Utilities
|
|||||||
- [Setup](#setup)
|
- [Setup](#setup)
|
||||||
- [Production](#production)
|
- [Production](#production)
|
||||||
- [Development](#development)
|
- [Development](#development)
|
||||||
- [Documentation](https://git.zakscode.com/ztimson/utils/wiki)
|
- [Documentation](https://utils.docs.zakscode.com/)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
@ -82,7 +82,7 @@ A collection of utilities to make life a little easier
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
[Available Here](https://git.zakscode.com/ztimson/utils/wiki)
|
[Available Here](https://utils.docs.zakscode.com/)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
1654
package-lock.json
generated
1654
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ztimson/utils",
|
"name": "@ztimson/utils",
|
||||||
"version": "0.16.3",
|
"version": "0.17.1",
|
||||||
"description": "Utility library",
|
"description": "Utility library",
|
||||||
"author": "Zak Timson",
|
"author": "Zak Timson",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npx tsc && npx vite build",
|
"build": "npx tsc && npx vite build",
|
||||||
"docs": "typedoc --plugin typedoc-plugin-markdown --cleanOutputDir false --outputFileStrategy modules --hidePageHeader --out ./docs --entryPoints src/**/*.ts --readme none --entryFileName Home",
|
"docs": "typedoc --cleanOutputDir false --out ./docs --entryPoints src/**/*.ts --readme none",
|
||||||
"test": "npx jest",
|
"test": "npx jest",
|
||||||
"test:coverage": "npx jest --coverage",
|
"test:coverage": "npx jest --coverage",
|
||||||
"watch": "npx vite build --watch"
|
"watch": "npx vite build --watch"
|
||||||
@ -32,12 +32,14 @@
|
|||||||
"jest-junit": "^16.0.0",
|
"jest-junit": "^16.0.0",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.1.2",
|
||||||
"typedoc": "^0.26.7",
|
"typedoc": "^0.26.7",
|
||||||
"typedoc-plugin-markdown": "^4.2.7",
|
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"vite": "^5.0.12",
|
"vite": "^5.0.12",
|
||||||
"vite-plugin-dts": "^3.7.2"
|
"vite-plugin-dts": "^3.7.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
]
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"var-persist": "^1.0.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
80
src/cache.ts
80
src/cache.ts
@ -1,8 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* Map of data which tracks whether it is a complete collection & offers optional expiry of cached values
|
* Map of data which tracks whether it is a complete collection & offers optional expiry of cached values
|
||||||
*/
|
*/
|
||||||
export class Cache<K, T> extends Map<K, T> {
|
export class Cache<K extends string | number | symbol, T> {
|
||||||
|
private store = <Record<K, T>>{};
|
||||||
|
|
||||||
|
/** Support index lookups */
|
||||||
|
[key: string | number | symbol]: T | any;
|
||||||
/** Whether cache is complete */
|
/** Whether cache is complete */
|
||||||
complete = false;
|
complete = false;
|
||||||
|
|
||||||
@ -12,11 +15,22 @@ export class Cache<K, T> extends Map<K, T> {
|
|||||||
* @param {keyof T} key Default property to use as primary key
|
* @param {keyof T} key Default property to use as primary key
|
||||||
* @param {number} ttl Default expiry in milliseconds
|
* @param {number} ttl Default expiry in milliseconds
|
||||||
*/
|
*/
|
||||||
constructor(public readonly key: keyof T, public ttl?: number) {
|
constructor(public readonly key?: keyof T, public ttl?: number) {
|
||||||
super();
|
return new Proxy(this, {
|
||||||
|
get: (target: this, prop: string | symbol) => {
|
||||||
|
if (prop in target) return (target as any)[prop];
|
||||||
|
return target.store[prop as K];
|
||||||
|
},
|
||||||
|
set: (target: this, prop: string | symbol, value: any) => {
|
||||||
|
if (prop in target) (target as any)[prop] = value;
|
||||||
|
else target.store[prop as K] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getKey(value: T): K {
|
private getKey(value: T): K {
|
||||||
|
if(!this.key) throw new Error('No key defined');
|
||||||
return <K>value[this.key];
|
return <K>value[this.key];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,8 +39,8 @@ export class Cache<K, T> extends Map<K, T> {
|
|||||||
*
|
*
|
||||||
* @return {T[]} Array of items
|
* @return {T[]} Array of items
|
||||||
*/
|
*/
|
||||||
all() {
|
all(): T[] {
|
||||||
return Array.from(this.values());
|
return Object.values(this.store);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,19 +69,71 @@ export class Cache<K, T> extends Map<K, T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an item from the cache
|
||||||
|
*
|
||||||
|
* @param {K} key Item's primary key
|
||||||
|
*/
|
||||||
|
delete(key: K) {
|
||||||
|
delete this.store[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return cache as an array of key-value pairs
|
||||||
|
* @return {[K, T][]} Key-value pairs array
|
||||||
|
*/
|
||||||
|
entries(): [K, T][] {
|
||||||
|
return <[K, T][]>Object.entries(this.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get item from the cache
|
||||||
|
* @param {K} key Key to lookup
|
||||||
|
* @return {T} Cached item
|
||||||
|
*/
|
||||||
|
get(key: K): T {
|
||||||
|
return this.store[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of cached keys
|
||||||
|
*
|
||||||
|
* @return {K[]} Array of keys
|
||||||
|
*/
|
||||||
|
keys(): K[] {
|
||||||
|
return <K[]>Object.keys(this.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get map of cached items
|
||||||
|
*
|
||||||
|
* @return {Record<K, T>}
|
||||||
|
*/
|
||||||
|
map(): Record<K, T> {
|
||||||
|
return structuredClone(this.store);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an item to the cache manually specifying the key
|
* Add an item to the cache manually specifying the key
|
||||||
|
*
|
||||||
* @param {K} key Key item will be cached under
|
* @param {K} key Key item will be cached under
|
||||||
* @param {T} value Item to cache
|
* @param {T} value Item to cache
|
||||||
* @param {number | undefined} ttl Override default expiry
|
* @param {number | undefined} ttl Override default expiry
|
||||||
* @return {this}
|
* @return {this}
|
||||||
*/
|
*/
|
||||||
set(key: K, value: T, ttl = this.ttl): this {
|
set(key: K, value: T, ttl = this.ttl): this {
|
||||||
super.set(key, value);
|
this.store[key] = value;
|
||||||
if(ttl) setTimeout(() => {
|
if(ttl) setTimeout(() => {
|
||||||
this.complete = false;
|
this.complete = false;
|
||||||
super.delete(key)
|
this.delete(key);
|
||||||
}, ttl);
|
}, ttl);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all cached items
|
||||||
|
*
|
||||||
|
* @return {T[]} Array of items
|
||||||
|
*/
|
||||||
|
values = this.all();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
export type Listener = (...args: any[]) => any;
|
export type Listener = (...args: any[]) => any;
|
||||||
export type TypedEvents = {[k in string | symbol]: Listener} & {'*': (event: string, ...args: any[]) => any};
|
export type TypedEvents = {[k in string | symbol]: Listener} & {'*': (event: string, ...args: any[]) => any};
|
||||||
|
|
||||||
|
export type NamespaceEvents<Namespace extends string, Events extends TypedEvents> = {
|
||||||
|
[K in keyof Events as `${Namespace}:${Extract<K, string>}`]: Events[K];
|
||||||
|
};
|
||||||
|
|
||||||
export class TypedEmitter<T extends TypedEvents = TypedEvents> {
|
export class TypedEmitter<T extends TypedEvents = TypedEvents> {
|
||||||
private static listeners: {[key: string]: Listener[]} = {};
|
private static listeners: {[key: string]: Listener[]} = {};
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ export * from './files';
|
|||||||
export * from './emitter';
|
export * from './emitter';
|
||||||
export * from './errors';
|
export * from './errors';
|
||||||
export * from './http';
|
export * from './http';
|
||||||
|
export * from './jwt';
|
||||||
export * from './logger';
|
export * from './logger';
|
||||||
export * from './math';
|
export * from './math';
|
||||||
export * from './misc';
|
export * from './misc';
|
||||||
@ -14,3 +15,4 @@ export * from './promise-progress';
|
|||||||
export * from './string';
|
export * from './string';
|
||||||
export * from './time';
|
export * from './time';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
export * from 'var-persist';
|
||||||
|
15
src/jwt.ts
Normal file
15
src/jwt.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import {JSONAttemptParse} from './objects.ts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode a JWT payload, this will not check for tampering so be careful
|
||||||
|
*
|
||||||
|
* @param {string} token JWT to decode
|
||||||
|
* @return {unknown} JWT payload
|
||||||
|
*/
|
||||||
|
export function jwtDecode<T>(token: string): T {
|
||||||
|
const base64 = token.split('.')[1]
|
||||||
|
.replace(/-/g, '+').replace(/_/g, '/');
|
||||||
|
return <T>JSONAttemptParse(decodeURIComponent(atob(base64).split('').map(function(c) {
|
||||||
|
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||||
|
}).join('')));
|
||||||
|
}
|
Reference in New Issue
Block a user