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,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Data URI parser.
*
* Based on:
* https://github.com/TooTallNate/node-data-uri-to-buffer/blob/main/src/index.ts (MIT)
*/
class DataURIParser {
/**
* Returns a Buffer instance from the given data URI `uri`.
*
* @param uri Data URI.
* @returns Buffer.
*/
static parse(uri) {
if (!/^data:/i.test(uri)) {
throw new TypeError('`uri` does not appear to be a Data URI (must begin with "data:")');
}
// Strip newlines
uri = uri.replace(/\r?\n/g, '');
// Split the URI up into the "metadata" and the "data" portions
const firstComma = uri.indexOf(',');
if (firstComma === -1 || firstComma <= 4) {
throw new TypeError('malformed data: URI');
}
// Remove the "data:" scheme and parse the metadata
const meta = uri.substring(5, firstComma).split(';');
let charset = '';
let base64 = false;
let type = meta[0] || 'text/plain';
for (let i = 1; i < meta.length; i++) {
if (meta[i] === 'base64') {
base64 = true;
}
else if (meta[i]) {
type += `;${meta[i]}`;
if (meta[i].indexOf('charset=') === 0) {
charset = meta[i].substring(8);
}
}
}
// Defaults to US-ASCII only if type is not provided
if (!meta[0] && !charset.length) {
type += ';charset=US-ASCII';
charset = 'US-ASCII';
}
// Get the encoded data portion and decode URI-encoded chars
const encoding = base64 ? 'base64' : 'ascii';
const data = unescape(uri.substring(firstComma + 1));
const buffer = Buffer.from(data, encoding);
return {
type,
charset,
buffer
};
}
}
exports.default = DataURIParser;
//# sourceMappingURL=DataURIParser.cjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DataURIParser.cjs","sourceRoot":"","sources":["../../../src/fetch/data-uri/DataURIParser.ts"],"names":[],"mappings":";;AAAA;;;;;GAKG;AACH,MAAqB,aAAa;IACjC;;;;;OAKG;IACI,MAAM,CAAC,KAAK,CAAC,GAAW;QAK9B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,SAAS,CAAC,kEAAkE,CAAC,CAAC;QACzF,CAAC;QAED,iBAAiB;QACjB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAEhC,+DAA+D;QAC/D,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,SAAS,CAAC,qBAAqB,CAAC,CAAC;QAC5C,CAAC;QAED,mDAAmD;QACnD,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrD,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC;QAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAC1B,MAAM,GAAG,IAAI,CAAC;YACf,CAAC;iBAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpB,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtB,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;oBACvC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAChC,CAAC;YACF,CAAC;QACF,CAAC;QAED,oDAAoD;QACpD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACjC,IAAI,IAAI,mBAAmB,CAAC;YAC5B,OAAO,GAAG,UAAU,CAAC;QACtB,CAAC;QAED,4DAA4D;QAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE3C,OAAO;YACN,IAAI;YACJ,OAAO;YACP,MAAM;SACN,CAAC;IACH,CAAC;CACD;AA3DD,gCA2DC"}

View File

@@ -0,0 +1,20 @@
/**
* Data URI parser.
*
* Based on:
* https://github.com/TooTallNate/node-data-uri-to-buffer/blob/main/src/index.ts (MIT)
*/
export default class DataURIParser {
/**
* Returns a Buffer instance from the given data URI `uri`.
*
* @param uri Data URI.
* @returns Buffer.
*/
static parse(uri: string): {
type: string;
charset: string;
buffer: Buffer;
};
}
//# sourceMappingURL=DataURIParser.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DataURIParser.d.ts","sourceRoot":"","sources":["../../../src/fetch/data-uri/DataURIParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,OAAO,OAAO,aAAa;IACjC;;;;;OAKG;WACW,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG;QACjC,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KACf;CAgDD"}