1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-11 05:59:15 +00:00

initial commit

This commit is contained in:
Elias Schneider
2024-08-12 11:00:25 +02:00
commit eaff977b22
241 changed files with 14378 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
export function debounced<T extends (...args: any[]) => void>(func: T, delay: number) {
let debounceTimeout: number | undefined;
return (...args: Parameters<T>) => {
if (debounceTimeout !== undefined) {
clearTimeout(debounceTimeout);
}
debounceTimeout = setTimeout(() => {
func(...args);
}, delay);
};
}

View File

@@ -0,0 +1,36 @@
import { WebAuthnError } from '@simplewebauthn/browser';
import { AxiosError } from 'axios';
import { toast } from 'svelte-sonner';
export function axiosErrorToast(e: unknown, message: string = 'An unknown error occurred') {
if (e instanceof AxiosError) {
message = e.response?.data.error || message;
}
toast.error(message);
}
export function getWebauthnErrorMessage(e: unknown) {
const errors = {
ERROR_CEREMONY_ABORTED: 'The authentication process was aborted',
ERROR_AUTHENTICATOR_GENERAL_ERROR: 'An error occurred with the authenticator',
ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT:
'The authenticator does not support discoverable credentials',
ERROR_AUTHENTICATOR_MISSING_RESIDENT_KEY_SUPPORT:
'The authenticator does not support resident keys',
ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED: 'This passkey was previously registered',
ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG:
'The authenticator does not support any of the requested algorithms'
};
let message = 'An unknown error occurred';
if (e instanceof WebAuthnError && e.code in errors) {
message = errors[e.code as keyof typeof errors];
} else if (e instanceof WebAuthnError && e?.message.includes('timed out')) {
message = 'The authenticator timed out';
} else if (e instanceof AxiosError && e.response?.data.error) {
message = e.response?.data.error;
} else {
console.error(e);
}
return message;
}

View File

@@ -0,0 +1,90 @@
import { writable } from 'svelte/store';
import { z } from 'zod';
export type FormInput<T> = {
value: T;
error: string | null;
};
type FormInputs<T> = {
[K in keyof T]: FormInput<T[K]>;
};
export function createForm<T extends z.ZodType<any, any>>(schema: T, initialValues: z.infer<T>) {
// Create a writable store for the inputs
const inputsStore = writable<FormInputs<z.infer<T>>>(initializeInputs(initialValues));
function initializeInputs(initialValues: z.infer<T>): FormInputs<z.infer<T>> {
const inputs: FormInputs<z.infer<T>> = {} as FormInputs<z.infer<T>>;
for (const key in initialValues) {
if (Object.prototype.hasOwnProperty.call(initialValues, key)) {
inputs[key as keyof z.infer<T>] = {
value: initialValues[key as keyof z.infer<T>],
error: null
};
}
}
return inputs;
}
function validate() {
let success = true;
inputsStore.update((inputs) => {
// Extract values from inputs to validate against the schema
const values = Object.fromEntries(
Object.entries(inputs).map(([key, input]) => [key, input.value])
);
const result = schema.safeParse(values);
if (!result.success) {
success = false;
for (const input of Object.keys(inputs)) {
const error = result.error.errors.find((e) => e.path[0] === input);
if (error) {
inputs[input as keyof z.infer<T>].error = error.message;
} else {
inputs[input as keyof z.infer<T>].error = null;
}
}
} else {
for (const input of Object.keys(inputs)) {
inputs[input as keyof z.infer<T>].error = null;
}
}
return inputs;
});
return success ? data() : null;
}
function data() {
let values: z.infer<T> | null = null;
inputsStore.subscribe((inputs) => {
values = Object.fromEntries(
Object.entries(inputs).map(([key, input]) => [key, input.value])
) as z.infer<T>;
})();
return values;
}
function reset() {
inputsStore.update((inputs) => {
for (const input of Object.keys(inputs)) {
inputs[input as keyof z.infer<T>] = {
value: initialValues[input as keyof z.infer<T>],
error: null
};
}
return inputs;
});
}
return {
schema,
inputs: inputsStore,
data,
validate,
reset
};
}

View File

@@ -0,0 +1,62 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { cubicOut } from "svelte/easing";
import type { TransitionConfig } from "svelte/transition";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
type FlyAndScaleParams = {
y?: number;
x?: number;
start?: number;
duration?: number;
};
export const flyAndScale = (
node: Element,
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
): TransitionConfig => {
const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform;
const scaleConversion = (
valueA: number,
scaleA: [number, number],
scaleB: [number, number]
) => {
const [minA, maxA] = scaleA;
const [minB, maxB] = scaleB;
const percentage = (valueA - minA) / (maxA - minA);
const valueB = percentage * (maxB - minB) + minB;
return valueB;
};
const styleToString = (
style: Record<string, number | string | undefined>
): string => {
return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined) return str;
return str + `${key}:${style[key]};`;
}, "");
};
return {
duration: params.duration ?? 200,
delay: 0,
css: (t) => {
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
return styleToString({
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
opacity: t
});
},
easing: cubicOut
};
};