@stackframe/stack-shared 1.0.0
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/LICENSE +7 -0
- package/dist/helpers/fetch-token.d.ts +1 -0
- package/dist/helpers/fetch-token.d.ts.map +1 -0
- package/dist/helpers/fetch-token.js +1 -0
- package/dist/helpers/password.d.ts +1 -0
- package/dist/helpers/password.d.ts.map +1 -0
- package/dist/helpers/password.js +33 -0
- package/dist/hooks/use-async-external-store.d.ts +4 -0
- package/dist/hooks/use-async-external-store.d.ts.map +1 -0
- package/dist/hooks/use-async-external-store.js +20 -0
- package/dist/hooks/use-strict-memo.d.ts +6 -0
- package/dist/hooks/use-strict-memo.d.ts.map +1 -0
- package/dist/hooks/use-strict-memo.js +64 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/interface/adminInterface.d.ts +88 -0
- package/dist/interface/adminInterface.d.ts.map +1 -0
- package/dist/interface/adminInterface.js +109 -0
- package/dist/interface/clientInterface.d.ts +134 -0
- package/dist/interface/clientInterface.d.ts.map +1 -0
- package/dist/interface/clientInterface.js +444 -0
- package/dist/interface/serverInterface.d.ts +33 -0
- package/dist/interface/serverInterface.d.ts.map +1 -0
- package/dist/interface/serverInterface.js +70 -0
- package/dist/utils/arrays.d.ts +10 -0
- package/dist/utils/arrays.d.ts.map +1 -0
- package/dist/utils/arrays.js +54 -0
- package/dist/utils/caches.d.ts +76 -0
- package/dist/utils/caches.d.ts.map +1 -0
- package/dist/utils/caches.js +100 -0
- package/dist/utils/crypto.d.ts +1 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +5 -0
- package/dist/utils/dates.d.ts +12 -0
- package/dist/utils/dates.d.ts.map +1 -0
- package/dist/utils/dates.js +57 -0
- package/dist/utils/dom.d.ts +4 -0
- package/dist/utils/dom.d.ts.map +1 -0
- package/dist/utils/dom.js +11 -0
- package/dist/utils/env.d.ts +4 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +7 -0
- package/dist/utils/errors.d.ts +184 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +72 -0
- package/dist/utils/html.d.ts +2 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +12 -0
- package/dist/utils/json.d.ts +10 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +26 -0
- package/dist/utils/jwt.d.ts +3 -0
- package/dist/utils/jwt.d.ts.map +1 -0
- package/dist/utils/jwt.js +16 -0
- package/dist/utils/math.d.ts +4 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +6 -0
- package/dist/utils/numbers.d.ts +2 -0
- package/dist/utils/numbers.d.ts.map +1 -0
- package/dist/utils/numbers.js +26 -0
- package/dist/utils/objects.d.ts +18 -0
- package/dist/utils/objects.d.ts.map +1 -0
- package/dist/utils/objects.js +63 -0
- package/dist/utils/password.d.ts +2 -0
- package/dist/utils/password.d.ts.map +1 -0
- package/dist/utils/password.js +8 -0
- package/dist/utils/promises.d.ts +49 -0
- package/dist/utils/promises.d.ts.map +1 -0
- package/dist/utils/promises.js +145 -0
- package/dist/utils/react.d.ts +12 -0
- package/dist/utils/react.d.ts.map +1 -0
- package/dist/utils/react.js +44 -0
- package/dist/utils/results.d.ts +73 -0
- package/dist/utils/results.d.ts.map +1 -0
- package/dist/utils/results.js +112 -0
- package/dist/utils/stores.d.ts +57 -0
- package/dist/utils/stores.d.ts.map +1 -0
- package/dist/utils/stores.js +122 -0
- package/dist/utils/strings.d.ts +40 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/utils/strings.js +91 -0
- package/dist/utils/types.d.ts +33 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +61 -0
- package/dist/utils/uuids.d.ts +1 -0
- package/dist/utils/uuids.d.ts.map +1 -0
- package/dist/utils/uuids.js +4 -0
- package/package.json +40 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { RateLimitOptions, ReactPromise } from "./promises";
|
|
2
|
+
import { ReadonlyAsyncStore } from "./stores";
|
|
3
|
+
export declare class AsyncCache<K extends object, T> {
|
|
4
|
+
private readonly _fetcher;
|
|
5
|
+
private readonly _rateLimitOptions;
|
|
6
|
+
private _map;
|
|
7
|
+
constructor(_fetcher: (key: K, isFirst: boolean) => Promise<T>, _rateLimitOptions?: Omit<RateLimitOptions, "batchCalls">);
|
|
8
|
+
private _createKeyed;
|
|
9
|
+
getValueCache(key: K): AsyncValueCache<T>;
|
|
10
|
+
isAvailable: (key: K) => boolean;
|
|
11
|
+
setUnavailable: (key: K) => void;
|
|
12
|
+
get: (key: K) => ({
|
|
13
|
+
status: "pending";
|
|
14
|
+
} & {
|
|
15
|
+
progress: void;
|
|
16
|
+
} & {
|
|
17
|
+
status: "pending";
|
|
18
|
+
}) | ({
|
|
19
|
+
status: "error";
|
|
20
|
+
error: unknown;
|
|
21
|
+
} & {
|
|
22
|
+
status: "error";
|
|
23
|
+
}) | ({
|
|
24
|
+
status: "ok";
|
|
25
|
+
data: T;
|
|
26
|
+
} & {
|
|
27
|
+
status: "ok";
|
|
28
|
+
});
|
|
29
|
+
getOrWait: (key: K) => ReactPromise<T>;
|
|
30
|
+
refresh: (key: K) => Promise<T>;
|
|
31
|
+
invalidate: (key: K) => Promise<T>;
|
|
32
|
+
onChange: (key: K, callback: (value: T, oldValue: T | undefined) => void) => {
|
|
33
|
+
unsubscribe: () => void;
|
|
34
|
+
};
|
|
35
|
+
onceChange: (key: K, callback: (value: T, oldValue: T | undefined) => void) => {
|
|
36
|
+
unsubscribe: () => void;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export declare class AsyncValueCache<T> implements ReadonlyAsyncStore<T> {
|
|
40
|
+
private readonly _rateLimitOptions;
|
|
41
|
+
private _store;
|
|
42
|
+
private _firstFetcher;
|
|
43
|
+
private _laterFetcher;
|
|
44
|
+
constructor(fetcher: (isFirst: boolean) => Promise<T>, _rateLimitOptions?: Omit<RateLimitOptions, "batchCalls">);
|
|
45
|
+
isAvailable(): boolean;
|
|
46
|
+
setUnavailable(): void;
|
|
47
|
+
get(): ({
|
|
48
|
+
status: "pending";
|
|
49
|
+
} & {
|
|
50
|
+
progress: void;
|
|
51
|
+
} & {
|
|
52
|
+
status: "pending";
|
|
53
|
+
}) | ({
|
|
54
|
+
status: "error";
|
|
55
|
+
error: unknown;
|
|
56
|
+
} & {
|
|
57
|
+
status: "error";
|
|
58
|
+
}) | ({
|
|
59
|
+
status: "ok";
|
|
60
|
+
data: T;
|
|
61
|
+
} & {
|
|
62
|
+
status: "ok";
|
|
63
|
+
});
|
|
64
|
+
getOrWait(): ReactPromise<T>;
|
|
65
|
+
private _set;
|
|
66
|
+
private _setAsync;
|
|
67
|
+
private _refetch;
|
|
68
|
+
refresh(): Promise<T>;
|
|
69
|
+
invalidate(): Promise<T>;
|
|
70
|
+
onChange(callback: (value: T, oldValue: T | undefined) => void): {
|
|
71
|
+
unsubscribe: () => void;
|
|
72
|
+
};
|
|
73
|
+
onceChange(callback: (value: T, oldValue: T | undefined) => void): {
|
|
74
|
+
unsubscribe: () => void;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caches.d.ts","sourceRoot":"","sources":["../../src/utils/caches.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAe,MAAM,YAAY,CAAC;AACzE,OAAO,EAAc,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE1D,qBAAa,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC;IAIvC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAJpC,OAAO,CAAC,IAAI,CAA6C;gBAGtC,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EAClD,iBAAiB,GAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAoC;IAK7G,OAAO,CAAC,YAAY;IASpB,aAAa,CAAC,GAAG,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAWzC,WAAW,QAlBF,CAAC,aAkBqC;IAC/C,cAAc,QAnBL,CAAC,UAmB2C;IACrD,GAAG,QApBM,CAAC;;;;;;;;;;;;;;;;OAoBqB;IAC/B,SAAS,QArBA,CAAC,qBAqBiC;IAC3C,OAAO,QAtBE,CAAC,gBAsB6B;IACvC,UAAU,QAvBD,CAAC,gBAuBmC;IAC7C,QAAQ,QAxBC,CAAC;;MAwB+B;IACzC,UAAU,QAzBD,CAAC;;MAyBmC;CAC9C;AAED,qBAAa,eAAe,CAAC,CAAC,CAAE,YAAW,kBAAkB,CAAC,CAAC,CAAC;IAO5D,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IANpC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,aAAa,CAAmB;gBAGtC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EACxB,iBAAiB,GAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAyC;IAmBlH,WAAW,IAAI,OAAO;IAItB,cAAc,IAAI,IAAI;IAItB,GAAG;;;;;;;;;;;;;;;;;IAIH,SAAS,IAAI,YAAY,CAAC,CAAC,CAAC;IAI5B,OAAO,CAAC,IAAI;YAIE,SAAS;YAIT,QAAQ;IAWhB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC;IAIrB,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC;IAK9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,GAAG;QAAE,WAAW,EAAE,MAAM,IAAI,CAAA;KAAE;IAI5F,UAAU,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,GAAG;QAAE,WAAW,EAAE,MAAM,IAAI,CAAA;KAAE;CAG/F"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { rateLimited } from "./promises";
|
|
2
|
+
import { AsyncStore } from "./stores";
|
|
3
|
+
export class AsyncCache {
|
|
4
|
+
_fetcher;
|
|
5
|
+
_rateLimitOptions;
|
|
6
|
+
_map = new Map();
|
|
7
|
+
constructor(_fetcher, _rateLimitOptions = { concurrency: 1, gapMs: 3_000 }) {
|
|
8
|
+
this._fetcher = _fetcher;
|
|
9
|
+
this._rateLimitOptions = _rateLimitOptions;
|
|
10
|
+
// nothing here yet
|
|
11
|
+
}
|
|
12
|
+
_createKeyed(functionName) {
|
|
13
|
+
return (key, ...args) => {
|
|
14
|
+
const valueCache = this.getValueCache(key);
|
|
15
|
+
return valueCache[functionName].apply(valueCache, args);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
getValueCache(key) {
|
|
19
|
+
let cache = this._map.get(key);
|
|
20
|
+
if (!cache) {
|
|
21
|
+
cache = new AsyncValueCache(async (isFirst) => {
|
|
22
|
+
return await this._fetcher(key, isFirst);
|
|
23
|
+
}, this._rateLimitOptions);
|
|
24
|
+
this._map.set(key, cache);
|
|
25
|
+
}
|
|
26
|
+
return cache;
|
|
27
|
+
}
|
|
28
|
+
isAvailable = this._createKeyed("isAvailable");
|
|
29
|
+
setUnavailable = this._createKeyed("setUnavailable");
|
|
30
|
+
get = this._createKeyed("get");
|
|
31
|
+
getOrWait = this._createKeyed("getOrWait");
|
|
32
|
+
refresh = this._createKeyed("refresh");
|
|
33
|
+
invalidate = this._createKeyed("invalidate");
|
|
34
|
+
onChange = this._createKeyed("onChange");
|
|
35
|
+
onceChange = this._createKeyed("onceChange");
|
|
36
|
+
}
|
|
37
|
+
export class AsyncValueCache {
|
|
38
|
+
_rateLimitOptions;
|
|
39
|
+
_store;
|
|
40
|
+
_firstFetcher;
|
|
41
|
+
_laterFetcher;
|
|
42
|
+
constructor(fetcher, _rateLimitOptions = { concurrency: 1, debounceMs: 3_000 }) {
|
|
43
|
+
this._rateLimitOptions = _rateLimitOptions;
|
|
44
|
+
this._store = new AsyncStore();
|
|
45
|
+
this._firstFetcher = async () => {
|
|
46
|
+
return await fetcher(true);
|
|
47
|
+
};
|
|
48
|
+
this._laterFetcher = rateLimited(async () => {
|
|
49
|
+
return await fetcher(false);
|
|
50
|
+
}, {
|
|
51
|
+
...this._rateLimitOptions,
|
|
52
|
+
batchCalls: true,
|
|
53
|
+
});
|
|
54
|
+
this._refetch(true).catch(() => {
|
|
55
|
+
this._store.setRejected(new Error("unavailable"));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
isAvailable() {
|
|
59
|
+
return this._store.isAvailable();
|
|
60
|
+
}
|
|
61
|
+
setUnavailable() {
|
|
62
|
+
this._store.setUnavailable();
|
|
63
|
+
}
|
|
64
|
+
get() {
|
|
65
|
+
return this._store.get();
|
|
66
|
+
}
|
|
67
|
+
getOrWait() {
|
|
68
|
+
return this._store.getOrWait();
|
|
69
|
+
}
|
|
70
|
+
_set(value) {
|
|
71
|
+
this._store.set(value);
|
|
72
|
+
}
|
|
73
|
+
async _setAsync(value) {
|
|
74
|
+
return await this._store.setAsync(value);
|
|
75
|
+
}
|
|
76
|
+
async _refetch(isFirst) {
|
|
77
|
+
try {
|
|
78
|
+
const res = isFirst ? this._firstFetcher() : this._laterFetcher();
|
|
79
|
+
await this._setAsync(res);
|
|
80
|
+
return await res;
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
this._store.setRejected(e);
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async refresh() {
|
|
88
|
+
return await this._refetch(false);
|
|
89
|
+
}
|
|
90
|
+
async invalidate() {
|
|
91
|
+
this.setUnavailable();
|
|
92
|
+
return await this._refetch(false);
|
|
93
|
+
}
|
|
94
|
+
onChange(callback) {
|
|
95
|
+
return this._store.onChange(callback);
|
|
96
|
+
}
|
|
97
|
+
onceChange(callback) {
|
|
98
|
+
return this._store.onceChange(callback);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateSecureRandomString(minBitsOfEntropy?: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.tsx"],"names":[],"mappings":"AAEA,wBAAgB,0BAA0B,CAAC,gBAAgB,GAAE,MAAY,UAGxE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function fromNow(date: Date): string;
|
|
2
|
+
export declare function fromNowDetailed(date: Date): {
|
|
3
|
+
result: string;
|
|
4
|
+
/**
|
|
5
|
+
* May be Infinity if the result will never change.
|
|
6
|
+
*/
|
|
7
|
+
secondsUntilChange: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Returns a string representation of the given date in the format expected by the `datetime-local` input type.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getInputDatetimeLocalString(date: Date): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/utils/dates.tsx"],"names":[],"mappings":"AAUA,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE1C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAuCA;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAI9D"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { remainder } from "./math";
|
|
2
|
+
const agoUnits = [
|
|
3
|
+
[60, 'second'],
|
|
4
|
+
[60, 'minute'],
|
|
5
|
+
[24, 'hour'],
|
|
6
|
+
[7, 'day'],
|
|
7
|
+
[5, 'week'],
|
|
8
|
+
];
|
|
9
|
+
export function fromNow(date) {
|
|
10
|
+
return fromNowDetailed(date).result;
|
|
11
|
+
}
|
|
12
|
+
export function fromNowDetailed(date) {
|
|
13
|
+
if (!(date instanceof Date)) {
|
|
14
|
+
throw new Error(`fromNow only accepts Date objects (received: ${date})`);
|
|
15
|
+
}
|
|
16
|
+
const now = new Date();
|
|
17
|
+
const elapsed = now.getTime() - date.getTime();
|
|
18
|
+
let remainingInUnit = Math.abs(elapsed) / 1000;
|
|
19
|
+
if (remainingInUnit < 15) {
|
|
20
|
+
return {
|
|
21
|
+
result: 'just now',
|
|
22
|
+
secondsUntilChange: 15 - remainingInUnit,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
let unitInSeconds = 1;
|
|
26
|
+
for (const [nextUnitSize, unitName] of agoUnits) {
|
|
27
|
+
const rounded = Math.round(remainingInUnit);
|
|
28
|
+
if (rounded < nextUnitSize) {
|
|
29
|
+
if (elapsed < 0) {
|
|
30
|
+
return {
|
|
31
|
+
result: `in ${rounded} ${unitName}${rounded === 1 ? '' : 's'}`,
|
|
32
|
+
secondsUntilChange: remainder((remainingInUnit - rounded + 0.5) * unitInSeconds, unitInSeconds),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return {
|
|
37
|
+
result: `${rounded} ${unitName}${rounded === 1 ? '' : 's'} ago`,
|
|
38
|
+
secondsUntilChange: remainder((rounded - remainingInUnit - 0.5) * unitInSeconds, unitInSeconds),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
unitInSeconds *= nextUnitSize;
|
|
43
|
+
remainingInUnit /= nextUnitSize;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
result: date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }),
|
|
47
|
+
secondsUntilChange: Infinity,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns a string representation of the given date in the format expected by the `datetime-local` input type.
|
|
52
|
+
*/
|
|
53
|
+
export function getInputDatetimeLocalString(date) {
|
|
54
|
+
date = new Date(date);
|
|
55
|
+
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
|
|
56
|
+
return date.toISOString().slice(0, 19);
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAMhE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* https://n2d4.github.io/frontend-starter/guides/advanced-concepts#clickable-parents
|
|
3
|
+
*/
|
|
4
|
+
export function hasClickableParent(element) {
|
|
5
|
+
const parent = element.parentElement;
|
|
6
|
+
if (!parent)
|
|
7
|
+
return false;
|
|
8
|
+
if (parent.dataset.n2Clickable)
|
|
9
|
+
return true;
|
|
10
|
+
return !!element.parentElement && hasClickableParent(element.parentElement);
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/utils/env.tsx"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { throwErr } from "./errors";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the environment variable with the given name, throwing an error if it's undefined or the empty string.
|
|
4
|
+
*/
|
|
5
|
+
export function getEnvVariable(name) {
|
|
6
|
+
return (process.env[name] ?? throwErr(`Missing environment variable: ${name}`)) || throwErr(`Empty environment variable: ${name}`);
|
|
7
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
export declare function throwErr(errorMessage: string): never;
|
|
2
|
+
export declare function throwErr(error: Error): never;
|
|
3
|
+
export declare function throwErr(...args: StatusErrorConstructorParameters): never;
|
|
4
|
+
type Status = {
|
|
5
|
+
statusCode: number;
|
|
6
|
+
message: string;
|
|
7
|
+
};
|
|
8
|
+
type StatusErrorConstructorParameters = [
|
|
9
|
+
statusCode: number | Status,
|
|
10
|
+
message?: string,
|
|
11
|
+
options?: {
|
|
12
|
+
headers: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
];
|
|
15
|
+
export declare class StatusError extends Error {
|
|
16
|
+
readonly options?: {
|
|
17
|
+
headers: Record<string, string>;
|
|
18
|
+
} | undefined;
|
|
19
|
+
readonly statusCode: number;
|
|
20
|
+
static BadRequest: {
|
|
21
|
+
statusCode: number;
|
|
22
|
+
message: string;
|
|
23
|
+
};
|
|
24
|
+
static Unauthorized: {
|
|
25
|
+
statusCode: number;
|
|
26
|
+
message: string;
|
|
27
|
+
};
|
|
28
|
+
static PaymentRequired: {
|
|
29
|
+
statusCode: number;
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
static Forbidden: {
|
|
33
|
+
statusCode: number;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
static NotFound: {
|
|
37
|
+
statusCode: number;
|
|
38
|
+
message: string;
|
|
39
|
+
};
|
|
40
|
+
static MethodNotAllowed: {
|
|
41
|
+
statusCode: number;
|
|
42
|
+
message: string;
|
|
43
|
+
};
|
|
44
|
+
static NotAcceptable: {
|
|
45
|
+
statusCode: number;
|
|
46
|
+
message: string;
|
|
47
|
+
};
|
|
48
|
+
static ProxyAuthenticationRequired: {
|
|
49
|
+
statusCode: number;
|
|
50
|
+
message: string;
|
|
51
|
+
};
|
|
52
|
+
static RequestTimeout: {
|
|
53
|
+
statusCode: number;
|
|
54
|
+
message: string;
|
|
55
|
+
};
|
|
56
|
+
static Conflict: {
|
|
57
|
+
statusCode: number;
|
|
58
|
+
message: string;
|
|
59
|
+
};
|
|
60
|
+
static Gone: {
|
|
61
|
+
statusCode: number;
|
|
62
|
+
message: string;
|
|
63
|
+
};
|
|
64
|
+
static LengthRequired: {
|
|
65
|
+
statusCode: number;
|
|
66
|
+
message: string;
|
|
67
|
+
};
|
|
68
|
+
static PreconditionFailed: {
|
|
69
|
+
statusCode: number;
|
|
70
|
+
message: string;
|
|
71
|
+
};
|
|
72
|
+
static PayloadTooLarge: {
|
|
73
|
+
statusCode: number;
|
|
74
|
+
message: string;
|
|
75
|
+
};
|
|
76
|
+
static URITooLong: {
|
|
77
|
+
statusCode: number;
|
|
78
|
+
message: string;
|
|
79
|
+
};
|
|
80
|
+
static UnsupportedMediaType: {
|
|
81
|
+
statusCode: number;
|
|
82
|
+
message: string;
|
|
83
|
+
};
|
|
84
|
+
static RangeNotSatisfiable: {
|
|
85
|
+
statusCode: number;
|
|
86
|
+
message: string;
|
|
87
|
+
};
|
|
88
|
+
static ExpectationFailed: {
|
|
89
|
+
statusCode: number;
|
|
90
|
+
message: string;
|
|
91
|
+
};
|
|
92
|
+
static ImATeapot: {
|
|
93
|
+
statusCode: number;
|
|
94
|
+
message: string;
|
|
95
|
+
};
|
|
96
|
+
static MisdirectedRequest: {
|
|
97
|
+
statusCode: number;
|
|
98
|
+
message: string;
|
|
99
|
+
};
|
|
100
|
+
static UnprocessableEntity: {
|
|
101
|
+
statusCode: number;
|
|
102
|
+
message: string;
|
|
103
|
+
};
|
|
104
|
+
static Locked: {
|
|
105
|
+
statusCode: number;
|
|
106
|
+
message: string;
|
|
107
|
+
};
|
|
108
|
+
static FailedDependency: {
|
|
109
|
+
statusCode: number;
|
|
110
|
+
message: string;
|
|
111
|
+
};
|
|
112
|
+
static TooEarly: {
|
|
113
|
+
statusCode: number;
|
|
114
|
+
message: string;
|
|
115
|
+
};
|
|
116
|
+
static UpgradeRequired: {
|
|
117
|
+
statusCode: number;
|
|
118
|
+
message: string;
|
|
119
|
+
};
|
|
120
|
+
static PreconditionRequired: {
|
|
121
|
+
statusCode: number;
|
|
122
|
+
message: string;
|
|
123
|
+
};
|
|
124
|
+
static TooManyRequests: {
|
|
125
|
+
statusCode: number;
|
|
126
|
+
message: string;
|
|
127
|
+
};
|
|
128
|
+
static RequestHeaderFieldsTooLarge: {
|
|
129
|
+
statusCode: number;
|
|
130
|
+
message: string;
|
|
131
|
+
};
|
|
132
|
+
static UnavailableForLegalReasons: {
|
|
133
|
+
statusCode: number;
|
|
134
|
+
message: string;
|
|
135
|
+
};
|
|
136
|
+
static InternalServerError: {
|
|
137
|
+
statusCode: number;
|
|
138
|
+
message: string;
|
|
139
|
+
};
|
|
140
|
+
static NotImplemented: {
|
|
141
|
+
statusCode: number;
|
|
142
|
+
message: string;
|
|
143
|
+
};
|
|
144
|
+
static BadGateway: {
|
|
145
|
+
statusCode: number;
|
|
146
|
+
message: string;
|
|
147
|
+
};
|
|
148
|
+
static ServiceUnavailable: {
|
|
149
|
+
statusCode: number;
|
|
150
|
+
message: string;
|
|
151
|
+
};
|
|
152
|
+
static GatewayTimeout: {
|
|
153
|
+
statusCode: number;
|
|
154
|
+
message: string;
|
|
155
|
+
};
|
|
156
|
+
static HTTPVersionNotSupported: {
|
|
157
|
+
statusCode: number;
|
|
158
|
+
message: string;
|
|
159
|
+
};
|
|
160
|
+
static VariantAlsoNegotiates: {
|
|
161
|
+
statusCode: number;
|
|
162
|
+
message: string;
|
|
163
|
+
};
|
|
164
|
+
static InsufficientStorage: {
|
|
165
|
+
statusCode: number;
|
|
166
|
+
message: string;
|
|
167
|
+
};
|
|
168
|
+
static LoopDetected: {
|
|
169
|
+
statusCode: number;
|
|
170
|
+
message: string;
|
|
171
|
+
};
|
|
172
|
+
static NotExtended: {
|
|
173
|
+
statusCode: number;
|
|
174
|
+
message: string;
|
|
175
|
+
};
|
|
176
|
+
static NetworkAuthenticationRequired: {
|
|
177
|
+
statusCode: number;
|
|
178
|
+
message: string;
|
|
179
|
+
};
|
|
180
|
+
constructor(...args: StatusErrorConstructorParameters);
|
|
181
|
+
isClientError(): boolean;
|
|
182
|
+
isServerError(): boolean;
|
|
183
|
+
}
|
|
184
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.tsx"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,KAAK,CAAC;AACtD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC;AAC9C,wBAAgB,QAAQ,CAAC,GAAG,IAAI,EAAE,gCAAgC,GAAG,KAAK,CAAC;AAY3E,KAAK,MAAM,GAAG;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,gCAAgC,GAAG;IACtC,UAAU,EAAE,MAAM,GAAG,MAAM;IAC3B,OAAO,CAAC,EAAE,MAAM;IAChB,OAAO,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;CAC9C,CAAC;AAEF,qBAAa,WAAY,SAAQ,KAAK;aA+CmC,OAAO,CAAC;iBAAa,OAAO,MAAM,EAAE,MAAM,CAAC;;IA9ClH,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC,OAAc,UAAU;;;MAA+C;IACvE,OAAc,YAAY;;;MAAgD;IAC1E,OAAc,eAAe;;;MAAoD;IACjF,OAAc,SAAS;;;MAA6C;IACpE,OAAc,QAAQ;;;MAA6C;IACnE,OAAc,gBAAgB;;;MAAsD;IACpF,OAAc,aAAa;;;MAAkD;IAC7E,OAAc,2BAA2B;;;MAAiE;IAC1G,OAAc,cAAc;;;MAAmD;IAC/E,OAAc,QAAQ;;;MAA4C;IAClE,OAAc,IAAI;;;MAAwC;IAC1D,OAAc,cAAc;;;MAAmD;IAC/E,OAAc,kBAAkB;;;MAAuD;IACvF,OAAc,eAAe;;;MAAqD;IAClF,OAAc,UAAU;;;MAAgD;IACxE,OAAc,oBAAoB;;;MAA0D;IAC5F,OAAc,mBAAmB;;;MAAyD;IAC1F,OAAc,iBAAiB;;;MAAsD;IACrF,OAAc,SAAS;;;MAAgD;IACvE,OAAc,kBAAkB;;;MAAuD;IACvF,OAAc,mBAAmB;;;MAAwD;IACzF,OAAc,MAAM;;;MAA0C;IAC9D,OAAc,gBAAgB;;;MAAqD;IACnF,OAAc,QAAQ;;;MAA6C;IACnE,OAAc,eAAe;;;MAAoD;IACjF,OAAc,oBAAoB;;;MAAyD;IAC3F,OAAc,eAAe;;;MAAqD;IAClF,OAAc,2BAA2B;;;MAAmE;IAC5G,OAAc,0BAA0B;;;MAAiE;IAEzG,OAAc,mBAAmB;;;MAAyD;IAC1F,OAAc,cAAc;;;MAAmD;IAC/E,OAAc,UAAU;;;MAA+C;IACvE,OAAc,kBAAkB;;;MAAuD;IACvF,OAAc,cAAc;;;MAAmD;IAC/E,OAAc,uBAAuB;;;MAA8D;IACnG,OAAc,qBAAqB;;;MAA2D;IAC9F,OAAc,mBAAmB;;;MAAwD;IACzF,OAAc,YAAY;;;MAAiD;IAC3E,OAAc,WAAW;;;MAAgD;IACzE,OAAc,6BAA6B;;;MAAmE;gBAGlG,GAAG,IAAI,EAAE,gCAAgC;IAW9C,aAAa;IAIb,aAAa;CAGrB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export function throwErr(...args) {
|
|
2
|
+
if (typeof args[0] === "string") {
|
|
3
|
+
throw new Error(args[0]);
|
|
4
|
+
}
|
|
5
|
+
else if (args[0] instanceof Error) {
|
|
6
|
+
throw args[0];
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
// @ts-expect-error
|
|
10
|
+
throw new StatusError(...args);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class StatusError extends Error {
|
|
14
|
+
options;
|
|
15
|
+
statusCode;
|
|
16
|
+
static BadRequest = { statusCode: 400, message: "Bad Request" };
|
|
17
|
+
static Unauthorized = { statusCode: 401, message: "Unauthorized" };
|
|
18
|
+
static PaymentRequired = { statusCode: 402, message: "Payment Required" };
|
|
19
|
+
static Forbidden = { statusCode: 403, message: "Forbidden" };
|
|
20
|
+
static NotFound = { statusCode: 404, message: "Not Found" };
|
|
21
|
+
static MethodNotAllowed = { statusCode: 405, message: "Method Not Allowed" };
|
|
22
|
+
static NotAcceptable = { statusCode: 406, message: "Not Acceptable" };
|
|
23
|
+
static ProxyAuthenticationRequired = { statusCode: 407, message: "Proxy Authentication Required" };
|
|
24
|
+
static RequestTimeout = { statusCode: 408, message: "Request Timeout" };
|
|
25
|
+
static Conflict = { statusCode: 409, message: "Conflict" };
|
|
26
|
+
static Gone = { statusCode: 410, message: "Gone" };
|
|
27
|
+
static LengthRequired = { statusCode: 411, message: "Length Required" };
|
|
28
|
+
static PreconditionFailed = { statusCode: 412, message: "Precondition Failed" };
|
|
29
|
+
static PayloadTooLarge = { statusCode: 413, message: "Payload Too Large" };
|
|
30
|
+
static URITooLong = { statusCode: 414, message: "URI Too Long" };
|
|
31
|
+
static UnsupportedMediaType = { statusCode: 415, message: "Unsupported Media Type" };
|
|
32
|
+
static RangeNotSatisfiable = { statusCode: 416, message: "Range Not Satisfiable" };
|
|
33
|
+
static ExpectationFailed = { statusCode: 417, message: "Expectation Failed" };
|
|
34
|
+
static ImATeapot = { statusCode: 418, message: "I'm a teapot" };
|
|
35
|
+
static MisdirectedRequest = { statusCode: 421, message: "Misdirected Request" };
|
|
36
|
+
static UnprocessableEntity = { statusCode: 422, message: "Unprocessable Entity" };
|
|
37
|
+
static Locked = { statusCode: 423, message: "Locked" };
|
|
38
|
+
static FailedDependency = { statusCode: 424, message: "Failed Dependency" };
|
|
39
|
+
static TooEarly = { statusCode: 425, message: "Too Early" };
|
|
40
|
+
static UpgradeRequired = { statusCode: 426, message: "Upgrade Required" };
|
|
41
|
+
static PreconditionRequired = { statusCode: 428, message: "Precondition Required" };
|
|
42
|
+
static TooManyRequests = { statusCode: 429, message: "Too Many Requests" };
|
|
43
|
+
static RequestHeaderFieldsTooLarge = { statusCode: 431, message: "Request Header Fields Too Large" };
|
|
44
|
+
static UnavailableForLegalReasons = { statusCode: 451, message: "Unavailable For Legal Reasons" };
|
|
45
|
+
static InternalServerError = { statusCode: 500, message: "Internal Server Error" };
|
|
46
|
+
static NotImplemented = { statusCode: 501, message: "Not Implemented" };
|
|
47
|
+
static BadGateway = { statusCode: 502, message: "Bad Gateway" };
|
|
48
|
+
static ServiceUnavailable = { statusCode: 503, message: "Service Unavailable" };
|
|
49
|
+
static GatewayTimeout = { statusCode: 504, message: "Gateway Timeout" };
|
|
50
|
+
static HTTPVersionNotSupported = { statusCode: 505, message: "HTTP Version Not Supported" };
|
|
51
|
+
static VariantAlsoNegotiates = { statusCode: 506, message: "Variant Also Negotiates" };
|
|
52
|
+
static InsufficientStorage = { statusCode: 507, message: "Insufficient Storage" };
|
|
53
|
+
static LoopDetected = { statusCode: 508, message: "Loop Detected" };
|
|
54
|
+
static NotExtended = { statusCode: 510, message: "Not Extended" };
|
|
55
|
+
static NetworkAuthenticationRequired = { statusCode: 511, message: "Network Authentication Required" };
|
|
56
|
+
constructor(status, message, options) {
|
|
57
|
+
if (typeof status === "object") {
|
|
58
|
+
message ??= status.message;
|
|
59
|
+
status = status.statusCode;
|
|
60
|
+
}
|
|
61
|
+
message ??= "Server Error";
|
|
62
|
+
super(message);
|
|
63
|
+
this.options = options;
|
|
64
|
+
this.statusCode = status;
|
|
65
|
+
}
|
|
66
|
+
isClientError() {
|
|
67
|
+
return this.statusCode >= 400 && this.statusCode < 500;
|
|
68
|
+
}
|
|
69
|
+
isServerError() {
|
|
70
|
+
return !this.isClientError();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/utils/html.tsx"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAE5E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { templateIdentity } from "./strings";
|
|
2
|
+
export function escapeHtml(unsafe) {
|
|
3
|
+
return `${unsafe}`
|
|
4
|
+
.replace(/&/g, '&')
|
|
5
|
+
.replace(/</g, '<')
|
|
6
|
+
.replace(/>/g, '>')
|
|
7
|
+
.replace(/"/g, """)
|
|
8
|
+
.replace(/'/g, "'");
|
|
9
|
+
}
|
|
10
|
+
export function html(strings, ...values) {
|
|
11
|
+
return templateIdentity(strings, ...values.map(v => escapeHtml(`${v}`)));
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "./results";
|
|
2
|
+
export type Json = null | boolean | number | string | Json[] | {
|
|
3
|
+
[key: string]: Json;
|
|
4
|
+
};
|
|
5
|
+
export type ReadonlyJson = null | boolean | number | string | readonly ReadonlyJson[] | {
|
|
6
|
+
readonly [key: string]: ReadonlyJson;
|
|
7
|
+
};
|
|
8
|
+
export declare function isJson(value: unknown): value is Json;
|
|
9
|
+
export declare function parseJson(json: string): Result<Json>;
|
|
10
|
+
export declare function stringifyJson(json: Json): Result<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/utils/json.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,MAAM,MAAM,IAAI,GACZ,IAAI,GACJ,OAAO,GACP,MAAM,GACN,MAAM,GACN,IAAI,EAAE,GACN;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE5B,MAAM,MAAM,YAAY,GACpB,IAAI,GACJ,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,YAAY,EAAE,GACvB;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAE7C,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAgBpD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAEpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAExD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Result } from "./results";
|
|
2
|
+
export function isJson(value) {
|
|
3
|
+
switch (typeof value) {
|
|
4
|
+
case "object": {
|
|
5
|
+
if (value === null)
|
|
6
|
+
return true;
|
|
7
|
+
if (Array.isArray(value))
|
|
8
|
+
return value.every(isJson);
|
|
9
|
+
return Object.keys(value).every(k => typeof k === "string") && Object.values(value).every(isJson);
|
|
10
|
+
}
|
|
11
|
+
case "string":
|
|
12
|
+
case "number":
|
|
13
|
+
case "boolean": {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
default: {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function parseJson(json) {
|
|
22
|
+
return Result.fromThrowing(() => JSON.parse(json));
|
|
23
|
+
}
|
|
24
|
+
export function stringifyJson(json) {
|
|
25
|
+
return Result.fromThrowing(() => JSON.stringify(json));
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/utils/jwt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAK7B,wBAAsB,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,SAAO,mBAMnE;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,4BAK3C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as jose from "jose";
|
|
2
|
+
import { getEnvVariable } from "./env";
|
|
3
|
+
const SERVER_SECRET = jose.base64url.decode(getEnvVariable("SERVER_SECRET"));
|
|
4
|
+
export async function encryptJWT(payload, expirationTime = "5m") {
|
|
5
|
+
return await new jose.EncryptJWT(payload)
|
|
6
|
+
.setProtectedHeader({ alg: "dir", enc: "A128CBC-HS256" })
|
|
7
|
+
.setIssuedAt()
|
|
8
|
+
.setExpirationTime(expirationTime)
|
|
9
|
+
.encrypt(SERVER_SECRET);
|
|
10
|
+
}
|
|
11
|
+
export async function decryptJWT(jwt) {
|
|
12
|
+
if (!jwt) {
|
|
13
|
+
throw new Error("Provided JWT is empty");
|
|
14
|
+
}
|
|
15
|
+
return (await jose.jwtDecrypt(jwt, SERVER_SECRET)).payload;
|
|
16
|
+
}
|