feat: Reinitialize frontend with SvelteKit and TypeScript

- Delete old Vite+Svelte frontend
- Initialize new SvelteKit project with TypeScript
- Configure Tailwind CSS v4 + DaisyUI
- Implement JWT authentication with auto-refresh
- Create login page with form validation (Zod)
- Add protected route guards
- Update Docker configuration for single-stage build
- Add E2E tests with Playwright (6/11 passing)
- Fix Svelte 5 reactivity with $state() runes

Known issues:
- 5 E2E tests failing (timing/async issues)
- Token refresh implementation needs debugging
- Validation error display timing
This commit is contained in:
2026-02-17 16:19:59 -05:00
parent 54df6018f5
commit de2d83092e
28274 changed files with 3816354 additions and 90 deletions

View File

@@ -0,0 +1,2 @@
export * from "./pure.js";
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":""}

View File

@@ -0,0 +1,103 @@
export * from "@testing-library/dom";
export { UnknownSvelteOptionsError } from "@testing-library/svelte-core";
/**
* Customize how Svelte renders the component.
*/
export type SvelteComponentOptions<C extends import("@testing-library/svelte-core/types").Component> = import("@testing-library/svelte-core/types").ComponentOptions<C>;
/**
* Customize how Testing Library sets up the document and binds queries.
*/
export type RenderOptions<Q extends DomTestingLibrary.Queries = typeof DomTestingLibrary.queries> = import("@testing-library/svelte-core/types").SetupOptions & {
queries?: Q;
};
/**
* The rendered component and bound testing functions.
*/
export type RenderResult<C extends import("@testing-library/svelte-core/types").Component, Q extends DomTestingLibrary.Queries = typeof DomTestingLibrary.queries> = {
container: HTMLElement;
baseElement: HTMLElement;
component: import("@testing-library/svelte-core/types").Exports<C>;
debug: (el?: HTMLElement | DocumentFragment) => void;
rerender: import("@testing-library/svelte-core/types").Rerender<C>;
unmount: () => void;
} & { [P in keyof Q]: DomTestingLibrary.BoundFunction<Q[P]>; };
export type FireFunction = (...args: Parameters<DomTestingLibrary.FireFunction>) => Promise<ReturnType<DomTestingLibrary.FireFunction>>;
export type FireObject = { [K in DomTestingLibrary.EventType]: (...args: Parameters<DomTestingLibrary.FireObject[K]>) => Promise<ReturnType<DomTestingLibrary.FireObject[K]>>; };
/**
* Call a function and wait for Svelte to flush pending changes.
*
* @template T
* @param {() => Promise<T> | T} [fn] - A function, which may be `async`, to call before flushing updates.
* @returns {Promise<T>}
*/
export function act<T>(fn?: () => Promise<T> | T): Promise<T>;
/** Unmount components, remove elements added to `<body>`, and reset `@testing-library/dom`. */
export function cleanup(): void;
/**
* @typedef {(...args: Parameters<DomTestingLibrary.FireFunction>) => Promise<ReturnType<DomTestingLibrary.FireFunction>>} FireFunction
*/
/**
* @typedef {{
* [K in DomTestingLibrary.EventType]: (...args: Parameters<DomTestingLibrary.FireObject[K]>) => Promise<ReturnType<DomTestingLibrary.FireObject[K]>>
* }} FireObject
*/
/**
* Fire an event on an element.
*
* Consider using `@testing-library/user-event` instead, if possible.
* @see https://testing-library.com/docs/user-event/intro/
*
* @type {FireFunction & FireObject}
*/
export const fireEvent: FireFunction & FireObject;
/**
* Customize how Svelte renders the component.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @typedef {import('@testing-library/svelte-core/types').ComponentOptions<C>} SvelteComponentOptions
*/
/**
* Customize how Testing Library sets up the document and binds queries.
*
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
* @typedef {import('@testing-library/svelte-core/types').SetupOptions & { queries?: Q }} RenderOptions
*/
/**
* The rendered component and bound testing functions.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
*
* @typedef {{
* container: HTMLElement
* baseElement: HTMLElement
* component: import('@testing-library/svelte-core/types').Exports<C>
* debug: (el?: HTMLElement | DocumentFragment) => void
* rerender: import('@testing-library/svelte-core/types').Rerender<C>
* unmount: () => void
* } & {
* [P in keyof Q]: DomTestingLibrary.BoundFunction<Q[P]>
* }} RenderResult
*/
/**
* Render a component into the document.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
*
* @param {import('@testing-library/svelte-core/types').ComponentImport<C>} Component - The component to render.
* @param {import('@testing-library/svelte-core/types').ComponentOptions<C>} options - Customize how Svelte renders the component.
* @param {RenderOptions<Q>} renderOptions - Customize how Testing Library sets up the document and binds queries.
* @returns {RenderResult<C, Q>} The rendered component and bound testing functions.
*/
export function render<C extends import("@testing-library/svelte-core/types").Component, Q extends DomTestingLibrary.Queries = typeof DomTestingLibrary.queries>(Component: import("@testing-library/svelte-core/types").ComponentImport<C>, options?: import("@testing-library/svelte-core/types").ComponentOptions<C>, renderOptions?: RenderOptions<Q>): RenderResult<C, Q>;
/**
* Configure `@testing-library/dom` for usage with Svelte.
*
* Ensures events fired from `@testing-library/dom`
* and `@testing-library/user-event` wait for Svelte
* to flush changes to the DOM before proceeding.
*/
export function setup(): void;
import * as DomTestingLibrary from '@testing-library/dom';
//# sourceMappingURL=pure.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"pure.d.ts","sourceRoot":"","sources":["../src/pure.js"],"names":[],"mappings":";;;;;mCAOsE,CAAC,SAA1D,OAAQ,oCAAoC,EAAE,SAAU,IACxD,OAAO,oCAAoC,EAAE,gBAAgB,CAAC,CAAC,CAAC;;;;0BAMnC,CAAC,SAA7B,iBAAiB,CAAC,OAAQ,uCAC3B,OAAO,oCAAoC,EAAE,YAAY,GAAG;IAAE,OAAO,CAAC,EAAE,CAAC,CAAA;CAAE;;;;yBAMlB,CAAC,SAA1D,OAAQ,oCAAoC,EAAE,SAAU,EAC3B,CAAC,SAA7B,iBAAiB,CAAC,OAAQ,uCAE3B;IACR,SAAS,EAAE,WAAW,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,SAAS,EAAE,OAAO,oCAAoC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAClE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,WAAW,GAAG,gBAAgB,KAAK,IAAI,CAAA;IACpD,QAAQ,EAAE,OAAO,oCAAoC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClE,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,GACD,CAAC,IAAI,MAAM,CAAC,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACtD;2BA+ES,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,iBAAiB,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;yBAI5G,GACP,CAAC,IAAI,iBAAiB,CAAC,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GACnJ;AAvBJ;;;;;;GAMG;AACH,oBAJa,CAAC,OACH,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAClB,OAAO,CAAC,CAAC,CAAC,CAStB;AAnBD,+FAA+F;AAC/F,gCAEC;AAkBD;;GAEG;AAEH;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAFU,YAAY,GAAG,UAAU,CAIlC;AA/HD;;;;;GAKG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;GAUG;AACH,uBARsE,CAAC,SAA1D,OAAQ,oCAAoC,EAAE,SAAU,EAC3B,CAAC,SAA7B,iBAAiB,CAAC,OAAQ,gDAE7B,OAAO,oCAAoC,EAAE,eAAe,CAAC,CAAC,CAAC,YAC/D,OAAO,oCAAoC,EAAE,gBAAgB,CAAC,CAAC,CAAC,kBAChE,aAAa,CAAC,CAAC,CAAC,GACd,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAuB9B;AAED;;;;;;GAMG;AACH,8BAWC;mCAxFkC,sBAAsB"}

View File

@@ -0,0 +1,6 @@
export function svelteTesting({ resolveBrowser, autoCleanup, noExternal, }?: {
resolveBrowser?: boolean;
autoCleanup?: boolean;
noExternal?: boolean;
}): import("vite").Plugin;
//# sourceMappingURL=vite.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.js"],"names":[],"mappings":"AAcO,6EAHI;IAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAC,GACrE,OAAO,MAAM,EAAE,MAAM,CAyBhC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=vitest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.js"],"names":[],"mappings":""}