diff --git a/block-01/week-01-the_web_under_the_hood/demo/.gitignore b/block-01/week-01-the_web_under_the_hood/demo/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/block-01/week-01-the_web_under_the_hood/demo/delay.html b/block-01/week-01-the_web_under_the_hood/demo/delay.html
new file mode 100644
index 0000000..36f156d
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/delay.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Delayed Response | Web Under the Hood
+
+
+
+ Delayed Response
+
+
+ This response was delayed by 5 seconds.
+
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/form-response.html b/block-01/week-01-the_web_under_the_hood/demo/form-response.html
new file mode 100644
index 0000000..2cc41fb
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/form-response.html
@@ -0,0 +1,8 @@
+
+ Server received your POST
+
+
+
+
+ ⚠️ Over plain HTTP, anyone between you and the server could read this.
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/form.html b/block-01/week-01-the_web_under_the_hood/demo/form.html
new file mode 100644
index 0000000..3e8cbee
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/form.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+ Form | Web Under the Hood
+
+
+
+
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/index.html b/block-01/week-01-the_web_under_the_hood/demo/index.html
new file mode 100644
index 0000000..0289762
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+ Web Under the Hood
+
+
+
+ HTTP Echo Server
+
+
+ Check your terminal - the server printed everything it received.
+ Try these:
+
+
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/package.json b/block-01/week-01-the_web_under_the_hood/demo/package.json
index f799e6d..63f1608 100644
--- a/block-01/week-01-the_web_under_the_hood/demo/package.json
+++ b/block-01/week-01-the_web_under_the_hood/demo/package.json
@@ -1,23 +1,23 @@
{
- "name": "week-01-the_web_under_the_hood-demo",
- "version": "1.0.0",
- "description": "",
- "main": "server.ts",
+ "name": "dem",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
"scripts": {
"dev": "tsx watch server.ts",
"build": "tsc server.ts --outDir dist",
"start": "node dist/server.js"
},
- "keywords": [],
- "author": "",
- "license": "ISC",
- "packageManager": "pnpm@10.22.0",
+ "devDependencies": {
+ "@tailwindcss/vite": "^4.3.1",
+ "@types/express": "^5.0.6",
+ "tailwindcss": "^4.3.1",
+ "tsx": "^4.22.4",
+ "typescript": "~6.0.2",
+ "vite": "^8.0.12"
+ },
"dependencies": {
"express": "^5.2.1",
"http-status": "^2.1.0"
- },
- "devDependencies": {
- "@types/express": "^5.0.6",
- "tsx": "^4.22.3"
}
}
\ No newline at end of file
diff --git a/block-01/week-01-the_web_under_the_hood/demo/pnpm-lock.yaml b/block-01/week-01-the_web_under_the_hood/demo/pnpm-lock.yaml
index f0a091e..69f6949 100644
--- a/block-01/week-01-the_web_under_the_hood/demo/pnpm-lock.yaml
+++ b/block-01/week-01-the_web_under_the_hood/demo/pnpm-lock.yaml
@@ -15,171 +15,402 @@ importers:
specifier: ^2.1.0
version: 2.1.0
devDependencies:
+ '@tailwindcss/vite':
+ specifier: ^4.3.1
+ version: 4.3.1(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4))
'@types/express':
specifier: ^5.0.6
version: 5.0.6
+ tailwindcss:
+ specifier: ^4.3.1
+ version: 4.3.1
tsx:
- specifier: ^4.22.3
- version: 4.22.3
+ specifier: ^4.22.4
+ version: 4.22.4
+ typescript:
+ specifier: ~6.0.2
+ version: 6.0.3
+ vite:
+ specifier: ^8.0.12
+ version: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)
packages:
- '@esbuild/aix-ppc64@0.28.0':
- resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==}
+ '@emnapi/core@1.10.0':
+ resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
+
+ '@emnapi/runtime@1.10.0':
+ resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
+
+ '@emnapi/wasi-threads@1.2.1':
+ resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
+
+ '@esbuild/aix-ppc64@0.28.1':
+ resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.28.0':
- resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==}
+ '@esbuild/android-arm64@0.28.1':
+ resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.28.0':
- resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==}
+ '@esbuild/android-arm@0.28.1':
+ resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.28.0':
- resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==}
+ '@esbuild/android-x64@0.28.1':
+ resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.28.0':
- resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==}
+ '@esbuild/darwin-arm64@0.28.1':
+ resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.28.0':
- resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==}
+ '@esbuild/darwin-x64@0.28.1':
+ resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.28.0':
- resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==}
+ '@esbuild/freebsd-arm64@0.28.1':
+ resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.28.0':
- resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==}
+ '@esbuild/freebsd-x64@0.28.1':
+ resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.28.0':
- resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==}
+ '@esbuild/linux-arm64@0.28.1':
+ resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.28.0':
- resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==}
+ '@esbuild/linux-arm@0.28.1':
+ resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.28.0':
- resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==}
+ '@esbuild/linux-ia32@0.28.1':
+ resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.28.0':
- resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==}
+ '@esbuild/linux-loong64@0.28.1':
+ resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.28.0':
- resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==}
+ '@esbuild/linux-mips64el@0.28.1':
+ resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.28.0':
- resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==}
+ '@esbuild/linux-ppc64@0.28.1':
+ resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.28.0':
- resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==}
+ '@esbuild/linux-riscv64@0.28.1':
+ resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.28.0':
- resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==}
+ '@esbuild/linux-s390x@0.28.1':
+ resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.28.0':
- resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==}
+ '@esbuild/linux-x64@0.28.1':
+ resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.28.0':
- resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==}
+ '@esbuild/netbsd-arm64@0.28.1':
+ resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.28.0':
- resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==}
+ '@esbuild/netbsd-x64@0.28.1':
+ resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.28.0':
- resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==}
+ '@esbuild/openbsd-arm64@0.28.1':
+ resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.28.0':
- resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==}
+ '@esbuild/openbsd-x64@0.28.1':
+ resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/openharmony-arm64@0.28.0':
- resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==}
+ '@esbuild/openharmony-arm64@0.28.1':
+ resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
- '@esbuild/sunos-x64@0.28.0':
- resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==}
+ '@esbuild/sunos-x64@0.28.1':
+ resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.28.0':
- resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==}
+ '@esbuild/win32-arm64@0.28.1':
+ resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.28.0':
- resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==}
+ '@esbuild/win32-ia32@0.28.1':
+ resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.28.0':
- resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==}
+ '@esbuild/win32-x64@0.28.1':
+ resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@napi-rs/wasm-runtime@1.1.5':
+ resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==}
+ peerDependencies:
+ '@emnapi/core': ^1.7.1
+ '@emnapi/runtime': ^1.7.1
+
+ '@oxc-project/types@0.133.0':
+ resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==}
+
+ '@rolldown/binding-android-arm64@1.0.3':
+ resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@rolldown/binding-darwin-arm64@1.0.3':
+ resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rolldown/binding-darwin-x64@1.0.3':
+ resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rolldown/binding-freebsd-x64@1.0.3':
+ resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.3':
+ resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.3':
+ resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-musl@1.0.3':
+ resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-ppc64-gnu@1.0.3':
+ resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rolldown/binding-linux-s390x-gnu@1.0.3':
+ resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-gnu@1.0.3':
+ resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-musl@1.0.3':
+ resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-openharmony-arm64@1.0.3':
+ resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rolldown/binding-wasm32-wasi@1.0.3':
+ resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [wasm32]
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.3':
+ resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rolldown/binding-win32-x64-msvc@1.0.3':
+ resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@rolldown/pluginutils@1.0.1':
+ resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
+
+ '@tailwindcss/node@4.3.1':
+ resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==}
+
+ '@tailwindcss/oxide-android-arm64@4.3.1':
+ resolution: {integrity: sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [android]
+
+ '@tailwindcss/oxide-darwin-arm64@4.3.1':
+ resolution: {integrity: sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-darwin-x64@4.3.1':
+ resolution: {integrity: sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-freebsd-x64@4.3.1':
+ resolution: {integrity: sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1':
+ resolution: {integrity: sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==}
+ engines: {node: '>= 20'}
+ cpu: [arm]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.1':
+ resolution: {integrity: sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.3.1':
+ resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.3.1':
+ resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-musl@4.3.1':
+ resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-wasm32-wasi@4.3.1':
+ resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+ bundledDependencies:
+ - '@napi-rs/wasm-runtime'
+ - '@emnapi/core'
+ - '@emnapi/runtime'
+ - '@tybys/wasm-util'
+ - '@emnapi/wasi-threads'
+ - tslib
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.1':
+ resolution: {integrity: sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.3.1':
+ resolution: {integrity: sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [win32]
+
+ '@tailwindcss/oxide@4.3.1':
+ resolution: {integrity: sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==}
+ engines: {node: '>= 20'}
+
+ '@tailwindcss/vite@4.3.1':
+ resolution: {integrity: sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==}
+ peerDependencies:
+ vite: ^5.2.0 || ^6 || ^7 || ^8
+
+ '@tybys/wasm-util@0.10.2':
+ resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
+
'@types/body-parser@1.19.6':
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
@@ -195,8 +426,8 @@ packages:
'@types/http-errors@2.0.5':
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
- '@types/node@25.9.1':
- resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==}
+ '@types/node@25.9.3':
+ resolution: {integrity: sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==}
'@types/qs@6.15.1':
resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==}
@@ -214,8 +445,8 @@ packages:
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
engines: {node: '>= 0.6'}
- body-parser@2.2.2:
- resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
+ body-parser@2.3.0:
+ resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==}
engines: {node: '>=18'}
bytes@3.1.2:
@@ -263,6 +494,10 @@ packages:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -274,6 +509,10 @@ packages:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
+ enhanced-resolve@5.21.6:
+ resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==}
+ engines: {node: '>=10.13.0'}
+
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
@@ -286,8 +525,8 @@ packages:
resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
engines: {node: '>= 0.4'}
- esbuild@0.28.0:
- resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==}
+ esbuild@0.28.1:
+ resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
engines: {node: '>=18'}
hasBin: true
@@ -302,6 +541,15 @@ packages:
resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
engines: {node: '>= 18'}
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
finalhandler@2.1.1:
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
engines: {node: '>= 18.0.0'}
@@ -334,12 +582,15 @@ packages:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
- hasown@2.0.3:
- resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
+ hasown@2.0.4:
+ resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
engines: {node: '>= 0.4'}
http-errors@2.0.1:
@@ -364,6 +615,83 @@ packages:
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+ jiti@2.7.0:
+ resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
+ hasBin: true
+
+ lightningcss-android-arm64@1.32.0:
+ resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.32.0:
+ resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.32.0:
+ resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.32.0:
+ resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.32.0:
+ resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.32.0:
+ resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.32.0:
+ resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.32.0:
+ resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.32.0:
+ resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.32.0:
+ resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.32.0:
+ resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.32.0:
+ resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
+ engines: {node: '>= 12.0.0'}
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@@ -387,6 +715,11 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ nanoid@3.3.12:
+ resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
negotiator@1.0.0:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
@@ -409,6 +742,17 @@ packages:
path-to-regexp@8.4.2:
resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@4.0.4:
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
+ engines: {node: '>=12'}
+
+ postcss@8.5.15:
+ resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
+ engines: {node: ^10 || ^12 || >=14}
+
proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
@@ -425,6 +769,11 @@ packages:
resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
engines: {node: '>= 0.10'}
+ rolldown@1.0.3:
+ resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
router@2.2.0:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
@@ -455,20 +804,38 @@ packages:
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
engines: {node: '>= 0.4'}
- side-channel@1.1.0:
- resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ side-channel@1.1.1:
+ resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==}
engines: {node: '>= 0.4'}
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
statuses@2.0.2:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
+ tailwindcss@4.3.1:
+ resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==}
+
+ tapable@2.3.3:
+ resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
+ engines: {node: '>=6'}
+
+ tinyglobby@0.2.17:
+ resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
+ engines: {node: '>=12.0.0'}
+
toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
- tsx@4.22.3:
- resolution: {integrity: sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==}
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ tsx@4.22.4:
+ resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==}
engines: {node: '>=18.0.0'}
hasBin: true
@@ -476,6 +843,11 @@ packages:
resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==}
engines: {node: '>= 18'}
+ typescript@6.0.3:
+ resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
undici-types@7.24.6:
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
@@ -487,101 +859,312 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
+ vite@8.0.16:
+ resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ '@vitejs/devtools': ^0.1.18
+ esbuild: ^0.27.0 || ^0.28.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ '@vitejs/devtools':
+ optional: true
+ esbuild:
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
snapshots:
- '@esbuild/aix-ppc64@0.28.0':
+ '@emnapi/core@1.10.0':
+ dependencies:
+ '@emnapi/wasi-threads': 1.2.1
+ tslib: 2.8.1
optional: true
- '@esbuild/android-arm64@0.28.0':
+ '@emnapi/runtime@1.10.0':
+ dependencies:
+ tslib: 2.8.1
optional: true
- '@esbuild/android-arm@0.28.0':
+ '@emnapi/wasi-threads@1.2.1':
+ dependencies:
+ tslib: 2.8.1
optional: true
- '@esbuild/android-x64@0.28.0':
+ '@esbuild/aix-ppc64@0.28.1':
optional: true
- '@esbuild/darwin-arm64@0.28.0':
+ '@esbuild/android-arm64@0.28.1':
optional: true
- '@esbuild/darwin-x64@0.28.0':
+ '@esbuild/android-arm@0.28.1':
optional: true
- '@esbuild/freebsd-arm64@0.28.0':
+ '@esbuild/android-x64@0.28.1':
optional: true
- '@esbuild/freebsd-x64@0.28.0':
+ '@esbuild/darwin-arm64@0.28.1':
optional: true
- '@esbuild/linux-arm64@0.28.0':
+ '@esbuild/darwin-x64@0.28.1':
optional: true
- '@esbuild/linux-arm@0.28.0':
+ '@esbuild/freebsd-arm64@0.28.1':
optional: true
- '@esbuild/linux-ia32@0.28.0':
+ '@esbuild/freebsd-x64@0.28.1':
optional: true
- '@esbuild/linux-loong64@0.28.0':
+ '@esbuild/linux-arm64@0.28.1':
optional: true
- '@esbuild/linux-mips64el@0.28.0':
+ '@esbuild/linux-arm@0.28.1':
optional: true
- '@esbuild/linux-ppc64@0.28.0':
+ '@esbuild/linux-ia32@0.28.1':
optional: true
- '@esbuild/linux-riscv64@0.28.0':
+ '@esbuild/linux-loong64@0.28.1':
optional: true
- '@esbuild/linux-s390x@0.28.0':
+ '@esbuild/linux-mips64el@0.28.1':
optional: true
- '@esbuild/linux-x64@0.28.0':
+ '@esbuild/linux-ppc64@0.28.1':
optional: true
- '@esbuild/netbsd-arm64@0.28.0':
+ '@esbuild/linux-riscv64@0.28.1':
optional: true
- '@esbuild/netbsd-x64@0.28.0':
+ '@esbuild/linux-s390x@0.28.1':
optional: true
- '@esbuild/openbsd-arm64@0.28.0':
+ '@esbuild/linux-x64@0.28.1':
optional: true
- '@esbuild/openbsd-x64@0.28.0':
+ '@esbuild/netbsd-arm64@0.28.1':
optional: true
- '@esbuild/openharmony-arm64@0.28.0':
+ '@esbuild/netbsd-x64@0.28.1':
optional: true
- '@esbuild/sunos-x64@0.28.0':
+ '@esbuild/openbsd-arm64@0.28.1':
optional: true
- '@esbuild/win32-arm64@0.28.0':
+ '@esbuild/openbsd-x64@0.28.1':
optional: true
- '@esbuild/win32-ia32@0.28.0':
+ '@esbuild/openharmony-arm64@0.28.1':
optional: true
- '@esbuild/win32-x64@0.28.0':
+ '@esbuild/sunos-x64@0.28.1':
+ optional: true
+
+ '@esbuild/win32-arm64@0.28.1':
+ optional: true
+
+ '@esbuild/win32-ia32@0.28.1':
+ optional: true
+
+ '@esbuild/win32-x64@0.28.1':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
+ dependencies:
+ '@emnapi/core': 1.10.0
+ '@emnapi/runtime': 1.10.0
+ '@tybys/wasm-util': 0.10.2
+ optional: true
+
+ '@oxc-project/types@0.133.0': {}
+
+ '@rolldown/binding-android-arm64@1.0.3':
+ optional: true
+
+ '@rolldown/binding-darwin-arm64@1.0.3':
+ optional: true
+
+ '@rolldown/binding-darwin-x64@1.0.3':
+ optional: true
+
+ '@rolldown/binding-freebsd-x64@1.0.3':
+ optional: true
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.3':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.3':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-musl@1.0.3':
+ optional: true
+
+ '@rolldown/binding-linux-ppc64-gnu@1.0.3':
+ optional: true
+
+ '@rolldown/binding-linux-s390x-gnu@1.0.3':
+ optional: true
+
+ '@rolldown/binding-linux-x64-gnu@1.0.3':
+ optional: true
+
+ '@rolldown/binding-linux-x64-musl@1.0.3':
+ optional: true
+
+ '@rolldown/binding-openharmony-arm64@1.0.3':
+ optional: true
+
+ '@rolldown/binding-wasm32-wasi@1.0.3':
+ dependencies:
+ '@emnapi/core': 1.10.0
+ '@emnapi/runtime': 1.10.0
+ '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
+ optional: true
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.3':
+ optional: true
+
+ '@rolldown/binding-win32-x64-msvc@1.0.3':
+ optional: true
+
+ '@rolldown/pluginutils@1.0.1': {}
+
+ '@tailwindcss/node@4.3.1':
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ enhanced-resolve: 5.21.6
+ jiti: 2.7.0
+ lightningcss: 1.32.0
+ magic-string: 0.30.21
+ source-map-js: 1.2.1
+ tailwindcss: 4.3.1
+
+ '@tailwindcss/oxide-android-arm64@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-arm64@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-x64@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-freebsd-x64@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-musl@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-wasm32-wasi@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.3.1':
+ optional: true
+
+ '@tailwindcss/oxide@4.3.1':
+ optionalDependencies:
+ '@tailwindcss/oxide-android-arm64': 4.3.1
+ '@tailwindcss/oxide-darwin-arm64': 4.3.1
+ '@tailwindcss/oxide-darwin-x64': 4.3.1
+ '@tailwindcss/oxide-freebsd-x64': 4.3.1
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.1
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.3.1
+ '@tailwindcss/oxide-linux-arm64-musl': 4.3.1
+ '@tailwindcss/oxide-linux-x64-gnu': 4.3.1
+ '@tailwindcss/oxide-linux-x64-musl': 4.3.1
+ '@tailwindcss/oxide-wasm32-wasi': 4.3.1
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1
+ '@tailwindcss/oxide-win32-x64-msvc': 4.3.1
+
+ '@tailwindcss/vite@4.3.1(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4))':
+ dependencies:
+ '@tailwindcss/node': 4.3.1
+ '@tailwindcss/oxide': 4.3.1
+ tailwindcss: 4.3.1
+ vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)
+
+ '@tybys/wasm-util@0.10.2':
+ dependencies:
+ tslib: 2.8.1
optional: true
'@types/body-parser@1.19.6':
dependencies:
'@types/connect': 3.4.38
- '@types/node': 25.9.1
+ '@types/node': 25.9.3
'@types/connect@3.4.38':
dependencies:
- '@types/node': 25.9.1
+ '@types/node': 25.9.3
'@types/express-serve-static-core@5.1.1':
dependencies:
- '@types/node': 25.9.1
+ '@types/node': 25.9.3
'@types/qs': 6.15.1
'@types/range-parser': 1.2.7
'@types/send': 1.2.1
@@ -594,7 +1177,7 @@ snapshots:
'@types/http-errors@2.0.5': {}
- '@types/node@25.9.1':
+ '@types/node@25.9.3':
dependencies:
undici-types: 7.24.6
@@ -604,22 +1187,22 @@ snapshots:
'@types/send@1.2.1':
dependencies:
- '@types/node': 25.9.1
+ '@types/node': 25.9.3
'@types/serve-static@2.2.0':
dependencies:
'@types/http-errors': 2.0.5
- '@types/node': 25.9.1
+ '@types/node': 25.9.3
accepts@2.0.0:
dependencies:
mime-types: 3.0.2
negotiator: 1.0.0
- body-parser@2.2.2:
+ body-parser@2.3.0:
dependencies:
bytes: 3.1.2
- content-type: 1.0.5
+ content-type: 2.0.0
debug: 4.4.3
http-errors: 2.0.1
iconv-lite: 0.7.2
@@ -658,6 +1241,8 @@ snapshots:
depd@2.0.0: {}
+ detect-libc@2.1.2: {}
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -668,6 +1253,11 @@ snapshots:
encodeurl@2.0.0: {}
+ enhanced-resolve@5.21.6:
+ dependencies:
+ graceful-fs: 4.2.11
+ tapable: 2.3.3
+
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
@@ -676,34 +1266,34 @@ snapshots:
dependencies:
es-errors: 1.3.0
- esbuild@0.28.0:
+ esbuild@0.28.1:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.28.0
- '@esbuild/android-arm': 0.28.0
- '@esbuild/android-arm64': 0.28.0
- '@esbuild/android-x64': 0.28.0
- '@esbuild/darwin-arm64': 0.28.0
- '@esbuild/darwin-x64': 0.28.0
- '@esbuild/freebsd-arm64': 0.28.0
- '@esbuild/freebsd-x64': 0.28.0
- '@esbuild/linux-arm': 0.28.0
- '@esbuild/linux-arm64': 0.28.0
- '@esbuild/linux-ia32': 0.28.0
- '@esbuild/linux-loong64': 0.28.0
- '@esbuild/linux-mips64el': 0.28.0
- '@esbuild/linux-ppc64': 0.28.0
- '@esbuild/linux-riscv64': 0.28.0
- '@esbuild/linux-s390x': 0.28.0
- '@esbuild/linux-x64': 0.28.0
- '@esbuild/netbsd-arm64': 0.28.0
- '@esbuild/netbsd-x64': 0.28.0
- '@esbuild/openbsd-arm64': 0.28.0
- '@esbuild/openbsd-x64': 0.28.0
- '@esbuild/openharmony-arm64': 0.28.0
- '@esbuild/sunos-x64': 0.28.0
- '@esbuild/win32-arm64': 0.28.0
- '@esbuild/win32-ia32': 0.28.0
- '@esbuild/win32-x64': 0.28.0
+ '@esbuild/aix-ppc64': 0.28.1
+ '@esbuild/android-arm': 0.28.1
+ '@esbuild/android-arm64': 0.28.1
+ '@esbuild/android-x64': 0.28.1
+ '@esbuild/darwin-arm64': 0.28.1
+ '@esbuild/darwin-x64': 0.28.1
+ '@esbuild/freebsd-arm64': 0.28.1
+ '@esbuild/freebsd-x64': 0.28.1
+ '@esbuild/linux-arm': 0.28.1
+ '@esbuild/linux-arm64': 0.28.1
+ '@esbuild/linux-ia32': 0.28.1
+ '@esbuild/linux-loong64': 0.28.1
+ '@esbuild/linux-mips64el': 0.28.1
+ '@esbuild/linux-ppc64': 0.28.1
+ '@esbuild/linux-riscv64': 0.28.1
+ '@esbuild/linux-s390x': 0.28.1
+ '@esbuild/linux-x64': 0.28.1
+ '@esbuild/netbsd-arm64': 0.28.1
+ '@esbuild/netbsd-x64': 0.28.1
+ '@esbuild/openbsd-arm64': 0.28.1
+ '@esbuild/openbsd-x64': 0.28.1
+ '@esbuild/openharmony-arm64': 0.28.1
+ '@esbuild/sunos-x64': 0.28.1
+ '@esbuild/win32-arm64': 0.28.1
+ '@esbuild/win32-ia32': 0.28.1
+ '@esbuild/win32-x64': 0.28.1
escape-html@1.0.3: {}
@@ -712,7 +1302,7 @@ snapshots:
express@5.2.1:
dependencies:
accepts: 2.0.0
- body-parser: 2.2.2
+ body-parser: 2.3.0
content-disposition: 1.1.0
content-type: 1.0.5
cookie: 0.7.2
@@ -742,6 +1332,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ fdir@6.5.0(picomatch@4.0.4):
+ optionalDependencies:
+ picomatch: 4.0.4
+
finalhandler@2.1.1:
dependencies:
debug: 4.4.3
@@ -772,7 +1366,7 @@ snapshots:
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
- hasown: 2.0.3
+ hasown: 2.0.4
math-intrinsics: 1.1.0
get-proto@1.0.1:
@@ -782,9 +1376,11 @@ snapshots:
gopd@1.2.0: {}
+ graceful-fs@4.2.11: {}
+
has-symbols@1.1.0: {}
- hasown@2.0.3:
+ hasown@2.0.4:
dependencies:
function-bind: 1.1.2
@@ -808,6 +1404,61 @@ snapshots:
is-promise@4.0.0: {}
+ jiti@2.7.0: {}
+
+ lightningcss-android-arm64@1.32.0:
+ optional: true
+
+ lightningcss-darwin-arm64@1.32.0:
+ optional: true
+
+ lightningcss-darwin-x64@1.32.0:
+ optional: true
+
+ lightningcss-freebsd-x64@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.32.0:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.32.0:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.32.0:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.32.0:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.32.0:
+ optional: true
+
+ lightningcss@1.32.0:
+ dependencies:
+ detect-libc: 2.1.2
+ optionalDependencies:
+ lightningcss-android-arm64: 1.32.0
+ lightningcss-darwin-arm64: 1.32.0
+ lightningcss-darwin-x64: 1.32.0
+ lightningcss-freebsd-x64: 1.32.0
+ lightningcss-linux-arm-gnueabihf: 1.32.0
+ lightningcss-linux-arm64-gnu: 1.32.0
+ lightningcss-linux-arm64-musl: 1.32.0
+ lightningcss-linux-x64-gnu: 1.32.0
+ lightningcss-linux-x64-musl: 1.32.0
+ lightningcss-win32-arm64-msvc: 1.32.0
+ lightningcss-win32-x64-msvc: 1.32.0
+
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
math-intrinsics@1.1.0: {}
media-typer@1.1.0: {}
@@ -822,6 +1473,8 @@ snapshots:
ms@2.1.3: {}
+ nanoid@3.3.12: {}
+
negotiator@1.0.0: {}
object-inspect@1.13.4: {}
@@ -838,6 +1491,16 @@ snapshots:
path-to-regexp@8.4.2: {}
+ picocolors@1.1.1: {}
+
+ picomatch@4.0.4: {}
+
+ postcss@8.5.15:
+ dependencies:
+ nanoid: 3.3.12
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
@@ -845,7 +1508,7 @@ snapshots:
qs@6.15.2:
dependencies:
- side-channel: 1.1.0
+ side-channel: 1.1.1
range-parser@1.2.1: {}
@@ -856,6 +1519,27 @@ snapshots:
iconv-lite: 0.7.2
unpipe: 1.0.0
+ rolldown@1.0.3:
+ dependencies:
+ '@oxc-project/types': 0.133.0
+ '@rolldown/pluginutils': 1.0.1
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.0.3
+ '@rolldown/binding-darwin-arm64': 1.0.3
+ '@rolldown/binding-darwin-x64': 1.0.3
+ '@rolldown/binding-freebsd-x64': 1.0.3
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.3
+ '@rolldown/binding-linux-arm64-gnu': 1.0.3
+ '@rolldown/binding-linux-arm64-musl': 1.0.3
+ '@rolldown/binding-linux-ppc64-gnu': 1.0.3
+ '@rolldown/binding-linux-s390x-gnu': 1.0.3
+ '@rolldown/binding-linux-x64-gnu': 1.0.3
+ '@rolldown/binding-linux-x64-musl': 1.0.3
+ '@rolldown/binding-openharmony-arm64': 1.0.3
+ '@rolldown/binding-wasm32-wasi': 1.0.3
+ '@rolldown/binding-win32-arm64-msvc': 1.0.3
+ '@rolldown/binding-win32-x64-msvc': 1.0.3
+
router@2.2.0:
dependencies:
debug: 4.4.3
@@ -915,7 +1599,7 @@ snapshots:
object-inspect: 1.13.4
side-channel-map: 1.0.1
- side-channel@1.1.0:
+ side-channel@1.1.1:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
@@ -923,13 +1607,27 @@ snapshots:
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
+ source-map-js@1.2.1: {}
+
statuses@2.0.2: {}
+ tailwindcss@4.3.1: {}
+
+ tapable@2.3.3: {}
+
+ tinyglobby@0.2.17:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
+
toidentifier@1.0.1: {}
- tsx@4.22.3:
+ tslib@2.8.1:
+ optional: true
+
+ tsx@4.22.4:
dependencies:
- esbuild: 0.28.0
+ esbuild: 0.28.1
optionalDependencies:
fsevents: 2.3.3
@@ -939,10 +1637,26 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.2
+ typescript@6.0.3: {}
+
undici-types@7.24.6: {}
unpipe@1.0.0: {}
vary@1.1.2: {}
+ vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4):
+ dependencies:
+ lightningcss: 1.32.0
+ picomatch: 4.0.4
+ postcss: 8.5.15
+ rolldown: 1.0.3
+ tinyglobby: 0.2.17
+ optionalDependencies:
+ '@types/node': 25.9.3
+ esbuild: 0.28.1
+ fsevents: 2.3.3
+ jiti: 2.7.0
+ tsx: 4.22.4
+
wrappy@1.0.2: {}
diff --git a/block-01/week-01-the_web_under_the_hood/demo/public/favicon.svg b/block-01/week-01-the_web_under_the_hood/demo/public/favicon.svg
new file mode 100644
index 0000000..6893eb1
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/public/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/block-01/week-01-the_web_under_the_hood/demo/public/icons.svg b/block-01/week-01-the_web_under_the_hood/demo/public/icons.svg
new file mode 100644
index 0000000..e952219
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/public/icons.svg
@@ -0,0 +1,24 @@
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/public/style.css b/block-01/week-01-the_web_under_the_hood/demo/public/style.css
deleted file mode 100644
index 1a37786..0000000
--- a/block-01/week-01-the_web_under_the_hood/demo/public/style.css
+++ /dev/null
@@ -1,76 +0,0 @@
-* {
- font-family: "Courier New", Courier, monospace;
- box-sizing: border-box;
-}
-
-body {
- background-color: #040b04;
- color: #7cff7c;
- text-shadow: 0 0 5px rgba(124, 255, 124, 0.35);
- line-height: 1.5;
- margin: 0;
- padding: 24px;
-}
-
-h1 {
- color: #a8ff9f;
- text-shadow: 0 0 8px rgba(124, 255, 124, 0.55);
-}
-
-p {
- color: #7cff7c;
- font-size: 18px;
-}
-
-a {
- color: #9fffa0;
- text-decoration: underline;
-}
-
-a:hover {
- color: #d6ffd6;
-}
-
-ul {
- list-style-type: square;
- padding-left: 24px;
-}
-
-::selection {
- background: rgba(124, 255, 124, 0.25);
- color: #ffffff;
-}
-
-form {
- margin-top: 16px;
- max-width: 400px;
-}
-
-label {
- display: flex;
- flex-direction: column;
- margin-bottom: 12px;
-}
-
-input {
- padding: 8px;
- border: 1px solid #7cff7c;
- background-color: transparent;
- color: #7cff7c;
- font-size: 16px;
- outline: none;
-}
-
-button {
- padding: 10px 16px;
- background-color: #7cff7c;
- color: #040b04;
- border: none;
- cursor: pointer;
- font-size: 16px;
- font-weight: bold;
-}
-
-button:hover {
- background-color: #9fffa0;
-}
diff --git a/block-01/week-01-the_web_under_the_hood/demo/server.ts b/block-01/week-01-the_web_under_the_hood/demo/server.ts
index 191a9d3..e177968 100644
--- a/block-01/week-01-the_web_under_the_hood/demo/server.ts
+++ b/block-01/week-01-the_web_under_the_hood/demo/server.ts
@@ -1,8 +1,17 @@
import express from "express"
+import fs from "fs/promises"
import { status } from "http-status"
+import { createServer as createViteServer } from "vite"
+import { injectIntoHtml } from "./src/utils/inject"
+import { partials } from "./src/plugins/injectPartials"
const app = express()
+const vite = await createViteServer({
+ server: { middlewareMode: true },
+ appType: "mpa",
+})
+
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
@@ -24,52 +33,22 @@ app.use((req, res, next) => {
next()
})
-// Serve static files from the "public" directory (for CSS, images, etc.)
-app.use(express.static("public"))
-
-// Simple GET: echoes request info back as HTML
-app.get("/", (req, res) => {
- res.send(`
-
- HTTP Echo Server
- Check your terminal — the server printed everything it received.
- Try these:
-
- `)
-})
-
-// Form page: allows to submit a POST and see the body
-app.get("/form", (req, res) => {
- res.send(`
-
- Login Form
-
- Submit this and watch the terminal. Also check DevTools → Network tab.
- `)
-})
-
// Receives the POST: echoes the body back
-app.post("/login", (req, res) => {
+app.post("/login", async (req, res) => {
const { username, password } = req.body
- res.send(`
-
- Server received your POST
- Username: ${username}
- Password: ${password}
- ⚠️ Over plain HTTP, anyone between you and the server could read this.
- Back
- `)
+ const base = await fs.readFile("src/partials/form-response.html", "utf-8")
+
+ let result = await injectIntoHtml(base, [
+ ...partials,
+ {
+ key: "",
+ placement: "replace",
+ type: "string",
+ value: JSON.stringify({ username, password }, null, 2),
+ },
+ ])
+
+ res.send(result)
})
// Sets a cookie: shows Set-Cookie header in DevTools
@@ -78,23 +57,25 @@ app.get("/set-cookie", (req, res) => {
httpOnly: true,
maxAge: 60 * 60 * 1000, // 1 hour
})
- res.send(`
-
- Cookie Set
- The server sent a Set-Cookie header. Check DevTools → Network → Response Headers.
- Now visit show-cookies — the browser will automatically send it back.
- `)
+ req.next?.()
})
// Shows what cookies the server received
-app.get("/show-cookies", (req, res) => {
+app.get("/show-cookies", async (req, res) => {
const cookieHeader = req.headers["cookie"] || "none"
- res.send(`
-
- Cookies the server received
- Cookie: ${cookieHeader}
- The browser sent this automatically — you didn't write any JavaScript for that.
- `)
+ const base = await fs.readFile("show-cookie.html", "utf-8")
+
+ let result = await injectIntoHtml(base, [
+ ...partials,
+ {
+ key: "",
+ placement: "replace",
+ type: "string",
+ value: cookieHeader,
+ },
+ ])
+
+ res.send(result)
})
// Returns JSON: shows Content-Type in action
@@ -110,68 +91,44 @@ app.get("/json", (req, res) => {
// Delayed response: simulates a slow server
app.get("/delay", (req, res) => {
setTimeout(() => {
- res.send(`
-
- Delayed Response
This response was delayed by 5 seconds.
- `)
+ req.next?.()
}, 5000)
})
-// Show all the different HTTP status codes
-app.get("/status", (req, res) => {
- res.send(`
-
- HTTP Status Codes
- 2xx Success
-
- ${[200, 201, 202, 203, 204, 205, 206, 207, 208, 226]
- .map(
- (code) =>
- `- ${code} ${status[code as keyof typeof status]}
`,
- )
- .join("")}
-
- 3xx Redirection
-
- 4xx Client Errors
-
- ${[
- 400, 401, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,
- 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,
- ]
- .map(
- (code) =>
- `- ${code} ${status[code as keyof typeof status]}
`,
- )
- .join("")}
-
- 5xx Server Errors
-
- ${[500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511]
- .map(
- (code) =>
- `- ${code} ${status[code as keyof typeof status]}
`,
- )
- .join("")}
-
- `)
+// Demonstrates different status codes
+app.get("/status/:code", async (req, res) => {
+ const code = parseInt(req.params.code)
+ const base = await fs.readFile("status-code.html", "utf-8")
+
+ let result = await injectIntoHtml(base, [
+ ...partials,
+ {
+ key: "",
+ placement: "replace",
+ type: "string",
+ value: code.toString(),
+ occurrence: "all",
+ },
+ {
+ key: "",
+ placement: "replace",
+ type: "string",
+ value: String(status[code as keyof typeof status]),
+ occurrence: "all",
+ },
+ {
+ key: "",
+ placement: "replace",
+ type: "string",
+ value: JSON.stringify(req.headers, null, 2),
+ occurrence: "all",
+ },
+ ])
+
+ res.status(code).send(result)
})
-// Demonstrates different status codes
-app.get("/status/:code", (req, res) => {
- const code = parseInt(req.params.code)
- res.status(code).send(`
-
- Status ${code}
This response was sent with HTTP status ${code} (${status[code as keyof typeof status]}).
- `)
-})
+app.use(vite.middlewares)
app.listen(3000, () => {
console.log("Echo server running on http://localhost:3000")
diff --git a/block-01/week-01-the_web_under_the_hood/demo/set-cookie.html b/block-01/week-01-the_web_under_the_hood/demo/set-cookie.html
new file mode 100644
index 0000000..574027e
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/set-cookie.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+ Set Cookie | Web Under the Hood
+
+
+
+ Cookie Set
+
+
+
+ The server sent a Set-Cookie header. Check DevTools → Network
+ → Response Headers.
+
+
+ Now visit show-cookies — the browser will
+ automatically send it back.
+
+
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/show-cookie.html b/block-01/week-01-the_web_under_the_hood/demo/show-cookie.html
new file mode 100644
index 0000000..b4c00bc
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/show-cookie.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+ Show Cookie | Web Under the Hood
+
+
+
+ Show Cookies
+
+
+ The server received the following cookies from the browser:
+
+
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/form.ts b/block-01/week-01-the_web_under_the_hood/demo/src/form.ts
new file mode 100644
index 0000000..8332ef5
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/form.ts
@@ -0,0 +1,25 @@
+document
+ .querySelector("#login-form")!
+ .addEventListener("submit", async (event) => {
+ event.preventDefault()
+ const form = event.currentTarget as HTMLFormElement
+ const formData = new FormData(form)
+ const data = Object.fromEntries(formData.entries())
+ console.log("Submitting form with data:", data)
+
+ const response = await fetch("/login", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data),
+ })
+
+ if (!response.ok) {
+ console.error("Login failed:", response.status, response.statusText)
+ return
+ }
+
+ const resultHtml = await response.text()
+ document.querySelector("#form-data")!.innerHTML = resultHtml
+ })
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/partials/blink.html b/block-01/week-01-the_web_under_the_hood/demo/src/partials/blink.html
new file mode 100644
index 0000000..4cbb9ae
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/partials/blink.html
@@ -0,0 +1 @@
+█
\ No newline at end of file
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/partials/form-response.html b/block-01/week-01-the_web_under_the_hood/demo/src/partials/form-response.html
new file mode 100644
index 0000000..2cc41fb
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/partials/form-response.html
@@ -0,0 +1,8 @@
+
+ Server received your POST
+
+
+
+
+ ⚠️ Over plain HTTP, anyone between you and the server could read this.
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/partials/navigation.html b/block-01/week-01-the_web_under_the_hood/demo/src/partials/navigation.html
new file mode 100644
index 0000000..072ab82
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/partials/navigation.html
@@ -0,0 +1,11 @@
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/plugins/injectPartials.ts b/block-01/week-01-the_web_under_the_hood/demo/src/plugins/injectPartials.ts
new file mode 100644
index 0000000..b70cfe2
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/plugins/injectPartials.ts
@@ -0,0 +1,48 @@
+import type { Plugin } from "vite"
+import { injectIntoHtml, type Injection } from "../utils/inject"
+
+export function injectPartials(injections: Injection[]): Plugin {
+ return {
+ name: "inject-partials",
+ transformIndexHtml(html) {
+ return injectIntoHtml(html, injections, {
+ onMissing: (key, occurrence) =>
+ this.warn(
+ `[inject-partials] Marker "${key}" (occurrence: ${occurrence}) not found — skipping.`,
+ ),
+ })
+ },
+ }
+}
+
+export const partials: Injection[] = [
+ {
+ key: "",
+ placement: "after",
+ type: "html",
+ path: "src/partials/navigation.html",
+ optional: true,
+ },
+ {
+ key: "",
+ placement: "before",
+ type: "string",
+ value: "",
+ optional: true,
+ },
+ {
+ key: "",
+ placement: "replace",
+ type: "html",
+ path: "src/partials/blink.html",
+ occurrence: "all",
+ optional: true,
+ },
+ {
+ key: "",
+ placement: "before",
+ type: "string",
+ value: "",
+ optional: true,
+ },
+]
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/status.ts b/block-01/week-01-the_web_under_the_hood/demo/src/status.ts
new file mode 100644
index 0000000..6c7cbb7
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/status.ts
@@ -0,0 +1,54 @@
+import { status } from "http-status"
+
+document.querySelector("#http-200")!.innerHTML = [
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
+]
+ .map(
+ (code) =>
+ `${code} ${status[code as keyof typeof status]}`,
+ )
+ .join("")
+
+document.querySelector("#http-300")!.innerHTML = [
+ 300, 301, 302, 303, 304, 307, 308,
+]
+ .map(
+ (code) => `
+
+ ${code} ${status[code as keyof typeof status]}
+
+ `,
+ )
+ .join("")
+
+document.querySelector("#http-400")!.innerHTML = [
+ 400, 401, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415,
+ 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,
+]
+ .map(
+ (code) => `
+
+ ${code} ${status[code as keyof typeof status]}
+
+ `,
+ )
+ .join("")
+
+document.querySelector("#http-500")!.innerHTML = [
+ 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,
+]
+ .map(
+ (code) =>
+ `
+
+ ${code} ${status[code as keyof typeof status]}
+
+ `,
+ )
+ .join("")
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/style.css b/block-01/week-01-the_web_under_the_hood/demo/src/style.css
new file mode 100644
index 0000000..2d20f2a
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/style.css
@@ -0,0 +1,165 @@
+@import url("https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap");
+@import "tailwindcss";
+
+@keyframes flicker {
+ 0%,
+ 95%,
+ 100% {
+ opacity: 1;
+ }
+ 96% {
+ opacity: 0.85;
+ }
+ 97% {
+ opacity: 1;
+ }
+ 98% {
+ opacity: 0.9;
+ }
+ 99% {
+ opacity: 1;
+ }
+}
+
+@keyframes scanline {
+ from {
+ transform: translateY(-100%);
+ }
+ to {
+ transform: translateY(100vh);
+ }
+}
+
+@keyframes blink {
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0;
+ }
+}
+
+* {
+ @apply box-border leading-[1.85] font-normal tracking-[0.04em];
+ @apply selection:bg-lime-800/40 selection:text-lime-200;
+ font-family: "Share Tech Mono", "Courier New", monospace;
+ color: #5abf00;
+ text-shadow: 0 0 5px rgba(90, 191, 0, 0.3);
+}
+
+body {
+ @apply relative p-6 bg-[#0a0a00];
+}
+
+/* scanlines */
+body::before {
+ @apply content-[''] fixed inset-0 pointer-events-none z-[9999];
+ background: repeating-linear-gradient(
+ 0deg,
+ transparent 0px,
+ transparent 2px,
+ rgba(0, 0, 0, 0.18) 2px,
+ rgba(0, 0, 0, 0.18) 4px
+ );
+}
+
+/* vignette */
+body::after {
+ @apply content-[''] fixed inset-0 pointer-events-none z-[9998];
+ background: radial-gradient(
+ ellipse at center,
+ transparent 55%,
+ rgba(0, 0, 0, 0.65) 100%
+ );
+}
+
+h1 {
+ @apply text-4xl font-normal tracking-[0.08em];
+ color: #a8ff40;
+ text-shadow:
+ 0 0 10px rgba(140, 255, 60, 0.55),
+ 0 0 22px rgba(140, 255, 60, 0.2);
+ animation: flicker 8s infinite;
+}
+
+h2 {
+ @apply text-xl font-normal tracking-[0.06em] border-b border-[#1a2a00] pb-1.5 mt-8;
+ color: #7dff40;
+ text-shadow: 0 0 8px rgba(120, 255, 60, 0.45);
+}
+
+a {
+ @apply border-b border-[#4a7a00] no-underline transition-colors duration-100;
+ color: #a8ff40;
+ text-shadow: 0 0 6px rgba(140, 255, 60, 0.4);
+}
+
+a:hover {
+ @apply border-[#8abf00];
+ color: #d4ff80;
+}
+
+ul {
+ @apply list-none pl-0;
+}
+
+ul li::before {
+ @apply content-['//\00a0'];
+ color: #2a4a00;
+}
+
+pre {
+ @apply bg-[#030300] border border-[#1a2a00] border-l-[3px] border-l-[#4a7a00] px-5 py-4 overflow-x-auto text-sm leading-[1.75];
+ color: #5abf00;
+}
+
+button {
+ @apply relative bg-transparent border border-[#4a7a00] px-5 py-2 text-xs tracking-[0.12em] uppercase cursor-pointer transition-all duration-100;
+ font-family: "Share Tech Mono", monospace;
+ color: #a8ff40;
+ text-shadow: 0 0 6px rgba(140, 255, 60, 0.4);
+ box-shadow:
+ inset 0 0 8px rgba(100, 200, 0, 0.05),
+ 0 0 6px rgba(100, 200, 0, 0.1);
+}
+
+button::before {
+ @apply content-['▶\00a0'] text-[0.7rem];
+ color: #4a7a00;
+}
+
+button:hover {
+ box-shadow:
+ inset 0 0 12px rgba(100, 200, 0, 0.1),
+ 0 0 10px rgba(100, 200, 0, 0.2);
+ background: rgba(100, 200, 0, 0.08);
+ border-color: #7dff40;
+}
+
+input {
+ @apply bg-transparent border-0 border-b border-[#2a4a00] pb-1 pt-1 text-sm outline-none transition-colors duration-150;
+ font-family: "Share Tech Mono", monospace;
+ color: #7dff40;
+ caret-color: #a8ff40;
+ text-shadow: 0 0 4px rgba(120, 255, 60, 0.3);
+}
+
+input:focus {
+ @apply border-[#7dff40];
+}
+
+input::placeholder {
+ @apply tracking-[0.1em];
+ color: #1a3000;
+}
+
+.blink {
+ animation: blink 1s step-end infinite;
+}
+
+.alert {
+ @apply text-sm mt-4 p-3 border border-[#7a7a00] bg-[#303000] rounded;
+ color: #ff9f40;
+ text-shadow: 0 0 4px rgba(255, 159, 64, 0.3);
+}
diff --git a/block-01/week-01-the_web_under_the_hood/demo/src/utils/inject.ts b/block-01/week-01-the_web_under_the_hood/demo/src/utils/inject.ts
new file mode 100644
index 0000000..e5ea863
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/src/utils/inject.ts
@@ -0,0 +1,146 @@
+import fs from "fs/promises"
+import path from "path"
+
+// ─── Types ────────────────────────────────────────────────────────────────────
+
+export type Placement = "before" | "after" | "replace"
+
+export type InjectionBase = {
+ key: string
+ placement: Placement
+ occurrence?: number | "all"
+ optional?: boolean
+}
+
+export type InjectionString = InjectionBase & {
+ type: "string"
+ value: string
+}
+
+export type InjectionHTML = InjectionBase & {
+ type: "html"
+ path: string
+}
+
+export type Injection = InjectionString | InjectionHTML
+
+// ─── Helpers ──────────────────────────────────────────────────────────────────
+
+function nthIndexOf(haystack: string, needle: string, n: number): number {
+ let index = -1
+ let remaining = n
+ let searchFrom = 0
+ while (remaining > 0) {
+ index = haystack.indexOf(needle, searchFrom)
+ if (index === -1) return -1
+ searchFrom = index + 1
+ remaining--
+ }
+ return index
+}
+
+function applyInjection(
+ html: string,
+ content: string,
+ markerIndex: number,
+ markerLength: number,
+ placement: Placement,
+): string {
+ switch (placement) {
+ case "before":
+ return html.slice(0, markerIndex) + content + html.slice(markerIndex)
+ case "after": {
+ const after = markerIndex + markerLength
+ return html.slice(0, after) + content + html.slice(after)
+ }
+ case "replace":
+ return (
+ html.slice(0, markerIndex) +
+ content +
+ html.slice(markerIndex + markerLength)
+ )
+ }
+}
+
+// ─── Core ─────────────────────────────────────────────────────────────────────
+
+export async function resolveContent(injection: Injection): Promise {
+ if (injection.type === "html") {
+ try {
+ return await fs.readFile(path.resolve(injection.path), "utf-8")
+ } catch (err) {
+ const message = err instanceof Error ? err.message : String(err)
+ throw new Error(`[inject] Failed to read "${injection.path}": ${message}`)
+ }
+ }
+ return injection.value
+}
+
+export type InjectOptions = {
+ /** Called when a marker is not found instead of throwing. Defaults to throwing. */
+ onMissing?: (key: string, occurrence: number | "all") => void
+}
+
+export async function injectIntoHtml(
+ html: string,
+ injections: Injection[],
+ options: InjectOptions = {},
+): Promise {
+ const contents = await Promise.all(injections.map(resolveContent))
+
+ for (let i = 0; i < injections.length; i++) {
+ const injection = injections[i]
+ const content = contents[i]
+ const occurrence = injection.occurrence ?? 1
+
+ const handleMissing = () => {
+ if (injection.optional) return
+
+ if (options.onMissing) {
+ options.onMissing(injection.key, occurrence)
+ } else {
+ throw new Error(
+ `[inject] Marker "${injection.key}" (occurrence: ${occurrence}) not found.`,
+ )
+ }
+ }
+
+ if (occurrence === "all") {
+ const indices: number[] = []
+ let searchFrom = 0
+ let idx: number
+ while ((idx = html.indexOf(injection.key, searchFrom)) !== -1) {
+ indices.push(idx)
+ searchFrom = idx + 1
+ }
+ if (indices.length === 0) {
+ handleMissing()
+ continue
+ }
+ for (let j = indices.length - 1; j >= 0; j--) {
+ html = applyInjection(
+ html,
+ content,
+ indices[j],
+ injection.key.length,
+ injection.placement,
+ )
+ }
+ } else {
+ const markerIndex = nthIndexOf(html, injection.key, occurrence)
+ if (markerIndex === -1) {
+ handleMissing()
+ continue
+ }
+ html = applyInjection(
+ html,
+ content,
+ markerIndex,
+ injection.key.length,
+ injection.placement,
+ )
+ }
+ }
+
+ return html
+}
diff --git a/block-01/week-01-the_web_under_the_hood/demo/status-code.html b/block-01/week-01-the_web_under_the_hood/demo/status-code.html
new file mode 100644
index 0000000..208cf28
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/status-code.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+ | Web Under the Hood
+
+
+
+ Status
+
+
+
+
+ This response was sent with HTTP status
+
+ ().
+
+ Headers
+
+
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/status.html b/block-01/week-01-the_web_under_the_hood/demo/status.html
new file mode 100644
index 0000000..92ab7a1
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/status.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+ HTTP Status Codes | Web Under the Hood
+
+
+
+ HTTP Status Codes
+
+
+ 2xx Success
+
+ 3xx Redirection
+
+ 4xx Client Errors
+
+ 5xx Server Errors
+
+
+
+
diff --git a/block-01/week-01-the_web_under_the_hood/demo/tsconfig.json b/block-01/week-01-the_web_under_the_hood/demo/tsconfig.json
new file mode 100644
index 0000000..1ab38c8
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "es2023",
+ "module": "esnext",
+ "lib": ["ES2023", "DOM"],
+ "types": ["vite/client"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/block-01/week-01-the_web_under_the_hood/demo/vite.config.ts b/block-01/week-01-the_web_under_the_hood/demo/vite.config.ts
new file mode 100644
index 0000000..61b4af4
--- /dev/null
+++ b/block-01/week-01-the_web_under_the_hood/demo/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from "vite"
+import tailwindcss from "@tailwindcss/vite"
+import { injectPartials, partials } from "./src/plugins/injectPartials"
+
+export default defineConfig({
+ plugins: [tailwindcss(), injectPartials(partials)],
+})