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,133 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const HTMLElement_js_1 = __importDefault(require("../html-element/HTMLElement.cjs"));
const PropertySymbol = __importStar(require("../../PropertySymbol.cjs"));
const EventPhaseEnum_js_1 = __importDefault(require("../../event/EventPhaseEnum.cjs"));
const MouseEvent_js_1 = __importDefault(require("../../event/events/MouseEvent.cjs"));
/**
* HTML Label Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement.
*/
class HTMLLabelElement extends HTMLElement_js_1.default {
/**
* Returns a string containing the ID of the labeled control. This reflects the "for" attribute.
*
* @returns ID of the labeled control.
*/
get htmlFor() {
const htmlFor = this.getAttribute('for');
if (htmlFor !== null) {
return htmlFor;
}
return htmlFor !== null ? htmlFor : '';
}
/**
* Sets a string containing the ID of the labeled control. This reflects the "for" attribute.
*
* @param htmlFor ID of the labeled control.
*/
set htmlFor(htmlFor) {
this.setAttribute('for', htmlFor);
}
/**
* Returns an HTML element representing the control with which the label is associated.
*
* @returns Control element.
*/
get control() {
const htmlFor = this.getAttribute('for');
if (htmlFor !== null) {
if (!htmlFor || !this[PropertySymbol.isConnected]) {
return null;
}
const control = (this[PropertySymbol.rootNode].getElementById(htmlFor));
if (control) {
switch (control[PropertySymbol.tagName]) {
case 'INPUT':
return control.type !== 'hidden' ? control : null;
case 'BUTTON':
case 'METER':
case 'OUTPUT':
case 'PROGRESS':
case 'SELECT':
case 'TEXTAREA':
return control;
default:
return null;
}
}
}
return (this.querySelector('button,input:not([type="hidden"]),meter,output,progress,select,textarea'));
}
/**
* Returns the parent form element.
*
* @returns Form.
*/
get form() {
return this.control?.form || null;
}
/**
* @override
*/
[PropertySymbol.cloneNode](deep = false) {
return super[PropertySymbol.cloneNode](deep);
}
/**
* @override
*/
dispatchEvent(event) {
const returnValue = super.dispatchEvent(event);
if (!event[PropertySymbol.defaultPrevented] &&
event.type === 'click' &&
(event.eventPhase === EventPhaseEnum_js_1.default.atTarget ||
event.eventPhase === EventPhaseEnum_js_1.default.bubbling) &&
event instanceof MouseEvent_js_1.default) {
const control = this.control;
if (control && event.target !== control) {
control.dispatchEvent(new MouseEvent_js_1.default('click', { bubbles: true, cancelable: true }));
}
}
return returnValue;
}
}
exports.default = HTMLLabelElement;
//# sourceMappingURL=HTMLLabelElement.cjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTMLLabelElement.cjs","sourceRoot":"","sources":["../../../src/nodes/html-label-element/HTMLLabelElement.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,53 @@
import HTMLElement from '../html-element/HTMLElement.cjs';
import * as PropertySymbol from '../../PropertySymbol.cjs';
import HTMLFormElement from '../html-form-element/HTMLFormElement.cjs';
import Event from '../../event/Event.cjs';
import HTMLInputElement from '../html-input-element/HTMLInputElement.cjs';
import HTMLButtonElement from '../html-button-element/HTMLButtonElement.cjs';
import HTMLMeterElement from '../html-meter-element/HTMLMeterElement.cjs';
import HTMLOutputElement from '../html-output-element/HTMLOutputElement.cjs';
import HTMLProgressElement from '../html-progress-element/HTMLProgressElement.cjs';
import HTMLSelectElement from '../html-select-element/HTMLSelectElement.cjs';
import HTMLTextAreaElement from '../html-text-area-element/HTMLTextAreaElement.cjs';
/**
* HTML Label Element.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement.
*/
export default class HTMLLabelElement extends HTMLElement {
cloneNode: (deep?: boolean) => HTMLLabelElement;
/**
* Returns a string containing the ID of the labeled control. This reflects the "for" attribute.
*
* @returns ID of the labeled control.
*/
get htmlFor(): string;
/**
* Sets a string containing the ID of the labeled control. This reflects the "for" attribute.
*
* @param htmlFor ID of the labeled control.
*/
set htmlFor(htmlFor: string);
/**
* Returns an HTML element representing the control with which the label is associated.
*
* @returns Control element.
*/
get control(): HTMLInputElement | HTMLButtonElement | HTMLMeterElement | HTMLOutputElement | HTMLProgressElement | HTMLSelectElement | HTMLTextAreaElement | null;
/**
* Returns the parent form element.
*
* @returns Form.
*/
get form(): HTMLFormElement | null;
/**
* @override
*/
[PropertySymbol.cloneNode](deep?: boolean): HTMLLabelElement;
/**
* @override
*/
dispatchEvent(event: Event): boolean;
}
//# sourceMappingURL=HTMLLabelElement.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTMLLabelElement.d.ts","sourceRoot":"","sources":["../../../src/nodes/html-label-element/HTMLLabelElement.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,gCAAgC,CAAC;AACzD,OAAO,KAAK,cAAc,MAAM,yBAAyB,CAAC;AAC1D,OAAO,eAAe,MAAM,yCAAyC,CAAC;AACtE,OAAO,KAAK,MAAM,sBAAsB,CAAC;AAEzC,OAAO,gBAAgB,MAAM,2CAA2C,CAAC;AAGzE,OAAO,iBAAiB,MAAM,6CAA6C,CAAC;AAC5E,OAAO,gBAAgB,MAAM,2CAA2C,CAAC;AACzE,OAAO,iBAAiB,MAAM,6CAA6C,CAAC;AAC5E,OAAO,mBAAmB,MAAM,iDAAiD,CAAC;AAClF,OAAO,iBAAiB,MAAM,6CAA6C,CAAC;AAC5E,OAAO,mBAAmB,MAAM,kDAAkD,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW;IAEzC,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,gBAAgB,CAAC;IAE/D;;;;OAIG;IACH,IAAW,OAAO,IAAI,MAAM,CAM3B;IAED;;;;OAIG;IACH,IAAW,OAAO,CAAC,OAAO,EAAE,MAAM,EAEjC;IAED;;;;OAIG;IACH,IAAW,OAAO,IACf,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,iBAAiB,GACjB,mBAAmB,GACnB,iBAAiB,GACjB,mBAAmB,GACnB,IAAI,CA4BN;IAED;;;;OAIG;IACH,IAAW,IAAI,IAAI,eAAe,GAAG,IAAI,CAExC;IAED;;OAEG;IACa,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,IAAI,UAAQ,GAAG,gBAAgB;IAI1E;;OAEG;IACa,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;CAkBpD"}

View File

@@ -0,0 +1,74 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const NodeList_js_1 = __importDefault(require("../node/NodeList.cjs"));
const PropertySymbol = __importStar(require("../../PropertySymbol.cjs"));
/**
* Utility for finding labels associated with a form element.
*/
class HTMLLabelElementUtility {
/**
* Returns label elements for a form element.
*
* @param element Element to get labels for.
* @returns Label elements.
*/
static getAssociatedLabelElements(element) {
const id = element.id;
let labels;
if (id && element[PropertySymbol.isConnected]) {
const rootNode = element[PropertySymbol.rootNode] ||
element[PropertySymbol.ownerDocument];
labels = (rootNode.querySelectorAll(`label[for="${id}"]`)[PropertySymbol.items]);
}
else {
labels = [];
}
let parent = element[PropertySymbol.parentNode];
while (parent) {
if (parent['tagName'] === 'LABEL') {
labels.push(parent);
break;
}
parent = parent[PropertySymbol.parentNode];
}
return new NodeList_js_1.default(PropertySymbol.illegalConstructor, labels);
}
}
exports.default = HTMLLabelElementUtility;
//# sourceMappingURL=HTMLLabelElementUtility.cjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTMLLabelElementUtility.cjs","sourceRoot":"","sources":["../../../src/nodes/html-label-element/HTMLLabelElementUtility.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,sEAA2C;AAE3C,wEAA0D;AAE1D;;GAEG;AACH,MAAqB,uBAAuB;IAC3C;;;;;OAKG;IACI,MAAM,CAAC,0BAA0B,CAAC,OAAoB;QAC5D,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QACtB,IAAI,MAA0B,CAAC;QAE/B,IAAI,EAAE,IAAI,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/C,MAAM,QAAQ,GACU,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC;gBACvD,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,GAAuB,CAC5B,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CACrE,CAAC;QACH,CAAC;aAAM,CAAC;YACP,MAAM,GAAG,EAAE,CAAC;QACb,CAAC;QAED,IAAI,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAChD,OAAO,MAAM,EAAE,CAAC;YACf,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,OAAO,EAAE,CAAC;gBACnC,MAAM,CAAC,IAAI,CAAmB,MAAM,CAAC,CAAC;gBACtC,MAAM;YACP,CAAC;YACD,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO,IAAI,qBAAQ,CAAmB,cAAc,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IAClF,CAAC;CACD;AAjCD,0CAiCC"}

View File

@@ -0,0 +1,16 @@
import HTMLElement from '../html-element/HTMLElement.cjs';
import HTMLLabelElement from './HTMLLabelElement.cjs';
import NodeList from '../node/NodeList.cjs';
/**
* Utility for finding labels associated with a form element.
*/
export default class HTMLLabelElementUtility {
/**
* Returns label elements for a form element.
*
* @param element Element to get labels for.
* @returns Label elements.
*/
static getAssociatedLabelElements(element: HTMLElement): NodeList<HTMLLabelElement>;
}
//# sourceMappingURL=HTMLLabelElementUtility.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTMLLabelElementUtility.d.ts","sourceRoot":"","sources":["../../../src/nodes/html-label-element/HTMLLabelElementUtility.ts"],"names":[],"mappings":"AACA,OAAO,WAAW,MAAM,gCAAgC,CAAC;AACzD,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AACrD,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAI3C;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,uBAAuB;IAC3C;;;;;OAKG;WACW,0BAA0B,CAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAC,gBAAgB,CAAC;CA0B1F"}