From 53ea5021d70c7fa4254771b9e70340f5a85838e4 Mon Sep 17 00:00:00 2001 From: Declan Teevan Date: Sun, 10 Aug 2025 10:50:52 +0100 Subject: [PATCH] feat: openapi-fetch typing feat: base page layout for implementation todo: fix light/dark mode toggling --- web/.env.example | 1 + web/package.json | 7 +- web/pnpm-lock.yaml | 219 ++- web/src/components/Footer.svelte | 10 + web/src/components/LightDarkMode.svelte | 26 + web/src/lib/api/client.ts | 8 + web/src/lib/api/schema.d.ts | 1614 +++++++++++++++++++++++ web/src/lib/config.ts | 3 + web/src/routes/+page.svelte | 100 +- web/src/stores/theme.ts | 35 + 10 files changed, 2010 insertions(+), 13 deletions(-) create mode 100644 web/.env.example create mode 100644 web/src/components/Footer.svelte create mode 100644 web/src/components/LightDarkMode.svelte create mode 100644 web/src/lib/api/client.ts create mode 100644 web/src/lib/api/schema.d.ts create mode 100644 web/src/lib/config.ts create mode 100644 web/src/stores/theme.ts diff --git a/web/.env.example b/web/.env.example new file mode 100644 index 0000000..02abd68 --- /dev/null +++ b/web/.env.example @@ -0,0 +1 @@ +PUBLIC_API_URL=http://localhost:80/ \ No newline at end of file diff --git a/web/package.json b/web/package.json index 10a9415..327f49d 100644 --- a/web/package.json +++ b/web/package.json @@ -11,7 +11,8 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "format": "prettier --write .", - "lint": "prettier --check . && eslint ." + "lint": "prettier --check . && eslint .", + "gen-openapi": "openapi-typescript ../schema/openapi/openapi.yaml -o ./src/lib/api/schema.d.ts" }, "devDependencies": { "@eslint/compat": "^1.2.5", @@ -29,6 +30,7 @@ "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^3.0.0", "globals": "^16.0.0", + "openapi-typescript": "^7.8.0", "prettier": "^3.4.2", "prettier-plugin-svelte": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.11", @@ -43,5 +45,8 @@ "onlyBuiltDependencies": [ "esbuild" ] + }, + "dependencies": { + "openapi-fetch": "^0.14.0" } } diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 7962a24..fbe5b9f 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -7,6 +7,10 @@ settings: importers: .: + dependencies: + openapi-fetch: + specifier: ^0.14.0 + version: 0.14.0 devDependencies: '@eslint/compat': specifier: ^1.2.5 @@ -53,6 +57,9 @@ importers: globals: specifier: ^16.0.0 version: 16.3.0 + openapi-typescript: + specifier: ^7.8.0 + version: 7.8.0(typescript@5.9.2) prettier: specifier: ^3.4.2 version: 3.6.2 @@ -87,6 +94,14 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + '@esbuild/aix-ppc64@0.25.8': resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} engines: {node: '>=18'} @@ -351,6 +366,16 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@redocly/ajv@8.11.3': + resolution: {integrity: sha512-4P3iZse91TkBiY+Dx5DUgxQ9GXkVJf++cmI0MOyLDxV9b5MUBI4II6ES8zA5JCbO72nKAJxWrw4PUPW+YP3ZDQ==} + + '@redocly/config@0.22.2': + resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==} + + '@redocly/openapi-core@1.34.5': + resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==} + engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@rollup/plugin-commonjs@28.0.6': resolution: {integrity: sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==} engines: {node: '>=16.0.0 || 14 >= 14.17'} @@ -827,9 +852,17 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -866,6 +899,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -885,6 +921,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -1091,6 +1130,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1107,6 +1150,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + index-to-position@1.1.0: + resolution: {integrity: sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==} + engines: {node: '>=18'} + is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -1139,6 +1186,13 @@ packages: resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} hasBin: true + js-levenshtein@1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -1149,6 +1203,9 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -1264,6 +1321,10 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -1300,6 +1361,18 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + openapi-fetch@0.14.0: + resolution: {integrity: sha512-PshIdm1NgdLvb05zp8LqRQMNSKzIlPkyMxYFxwyHR+UlKD4t2nUjkDhNxeRbhRSEd3x5EUNh2w5sJYwkhOH4fg==} + + openapi-typescript-helpers@0.0.15: + resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} + + openapi-typescript@7.8.0: + resolution: {integrity: sha512-1EeVWmDzi16A+siQlo/SwSGIT7HwaFAVjvMA7/jG5HMLSnrUOzPL7uSTRZZa4v/LCRxHTApHKtNY6glApEoiUQ==} + hasBin: true + peerDependencies: + typescript: ^5.x + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1316,6 +1389,10 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1338,6 +1415,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -1464,6 +1545,10 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1517,6 +1602,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + supports-color@10.1.0: + resolution: {integrity: sha512-GBuewsPrhJPftT+fqDa9oI/zc5HNsG9nREqwzoSFDOIqf0NggOZbHQj2TE1P1CDJK8ZogFnlZY9hWoUiur7I/A==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1579,6 +1668,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + typescript-eslint@8.39.0: resolution: {integrity: sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1591,6 +1684,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -1658,10 +1754,17 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -1676,6 +1779,14 @@ snapshots: '@jridgewell/gen-mapping': 0.3.12 '@jridgewell/trace-mapping': 0.3.29 + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.27.1': {} + '@esbuild/aix-ppc64@0.25.8': optional: true @@ -1768,7 +1879,7 @@ snapshots: '@eslint/config-array@0.21.0': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -1782,7 +1893,7 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -1858,6 +1969,29 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@redocly/ajv@8.11.3': + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js-replace: 1.0.1 + + '@redocly/config@0.22.2': {} + + '@redocly/openapi-core@1.34.5(supports-color@10.1.0)': + dependencies: + '@redocly/ajv': 8.11.3 + '@redocly/config': 0.22.2 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.1.0) + js-levenshtein: 1.1.6 + js-yaml: 4.1.0 + minimatch: 5.1.6 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + '@rollup/plugin-commonjs@28.0.6(rollup@4.46.2)': dependencies: '@rollup/pluginutils': 5.2.0(rollup@4.46.2) @@ -2023,7 +2157,7 @@ snapshots: '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1))': dependencies: '@sveltejs/vite-plugin-svelte': 6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1)) - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) svelte: 5.38.0 vite: 7.0.6(jiti@2.5.1)(lightningcss@1.30.1) transitivePeerDependencies: @@ -2032,7 +2166,7 @@ snapshots: '@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1))': dependencies: '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.1.0(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1)))(svelte@5.38.0)(vite@7.0.6(jiti@2.5.1)(lightningcss@1.30.1)) - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.17 @@ -2152,7 +2286,7 @@ snapshots: '@typescript-eslint/types': 8.39.0 '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.39.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) eslint: 9.32.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: @@ -2162,7 +2296,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) '@typescript-eslint/types': 8.39.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -2181,7 +2315,7 @@ snapshots: '@typescript-eslint/types': 8.39.0 '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) '@typescript-eslint/utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) eslint: 9.32.0(jiti@2.5.1) ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 @@ -2196,7 +2330,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) '@typescript-eslint/types': 8.39.0 '@typescript-eslint/visitor-keys': 8.39.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -2457,6 +2591,8 @@ snapshots: acorn@8.15.0: {} + agent-base@7.1.4: {} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -2464,6 +2600,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-colors@4.1.3: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -2496,6 +2634,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + change-case@5.4.4: {} + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -2510,6 +2650,8 @@ snapshots: color-name@1.1.4: {} + colorette@1.4.0: {} + commondir@1.0.1: {} concat-map@0.0.1: {} @@ -2526,9 +2668,11 @@ snapshots: csstype@3.1.3: {} - debug@4.4.1: + debug@4.4.1(supports-color@10.1.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.1.0 deep-is@0.1.4: {} @@ -2623,7 +2767,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.1.0) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -2742,6 +2886,13 @@ snapshots: dependencies: function-bind: 1.1.2 + https-proxy-agent@7.0.6(supports-color@10.1.0): + dependencies: + agent-base: 7.1.4 + debug: 4.4.1(supports-color@10.1.0) + transitivePeerDependencies: + - supports-color + ignore@5.3.2: {} ignore@7.0.5: {} @@ -2753,6 +2904,8 @@ snapshots: imurmurhash@0.1.4: {} + index-to-position@1.1.0: {} + is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -2779,6 +2932,10 @@ snapshots: jiti@2.5.1: {} + js-levenshtein@1.1.6: {} + + js-tokens@4.0.0: {} + js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -2787,6 +2944,8 @@ snapshots: json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} keyv@4.5.4: @@ -2876,6 +3035,10 @@ snapshots: dependencies: brace-expansion: 1.1.12 + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 @@ -2898,6 +3061,22 @@ snapshots: natural-compare@1.4.0: {} + openapi-fetch@0.14.0: + dependencies: + openapi-typescript-helpers: 0.0.15 + + openapi-typescript-helpers@0.0.15: {} + + openapi-typescript@7.8.0(typescript@5.9.2): + dependencies: + '@redocly/openapi-core': 1.34.5(supports-color@10.1.0) + ansi-colors: 4.1.3 + change-case: 5.4.4 + parse-json: 8.3.0 + supports-color: 10.1.0 + typescript: 5.9.2 + yargs-parser: 21.1.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2919,6 +3098,12 @@ snapshots: dependencies: callsites: 3.1.0 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.27.1 + index-to-position: 1.1.0 + type-fest: 4.41.0 + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -2931,6 +3116,8 @@ snapshots: picomatch@4.0.3: {} + pluralize@8.0.0: {} + postcss-load-config@3.1.4(postcss@8.5.6): dependencies: lilconfig: 2.1.0 @@ -2985,6 +3172,8 @@ snapshots: readdirp@4.1.2: {} + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} resolve@1.22.10: @@ -3049,6 +3238,8 @@ snapshots: strip-json-comments@3.1.1: {} + supports-color@10.1.0: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -3127,6 +3318,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@4.41.0: {} + typescript-eslint@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2): dependencies: '@typescript-eslint/eslint-plugin': 8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) @@ -3140,6 +3333,8 @@ snapshots: typescript@5.9.2: {} + uri-js-replace@1.0.1: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -3171,8 +3366,12 @@ snapshots: yallist@5.0.0: {} + yaml-ast-parser@0.0.43: {} + yaml@1.10.2: {} + yargs-parser@21.1.1: {} + yocto-queue@0.1.0: {} zimmerframe@1.1.2: {} diff --git a/web/src/components/Footer.svelte b/web/src/components/Footer.svelte new file mode 100644 index 0000000..64d385e --- /dev/null +++ b/web/src/components/Footer.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/web/src/components/LightDarkMode.svelte b/web/src/components/LightDarkMode.svelte new file mode 100644 index 0000000..c1ed221 --- /dev/null +++ b/web/src/components/LightDarkMode.svelte @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/web/src/lib/api/client.ts b/web/src/lib/api/client.ts new file mode 100644 index 0000000..c09ec8d --- /dev/null +++ b/web/src/lib/api/client.ts @@ -0,0 +1,8 @@ +import createClient from "openapi-fetch"; + +import type { paths } from "./schema.d"; +import { API_URL } from "../config"; + +const client = createClient({ baseUrl: API_URL }); + +export default client; \ No newline at end of file diff --git a/web/src/lib/api/schema.d.ts b/web/src/lib/api/schema.d.ts new file mode 100644 index 0000000..130c9b5 --- /dev/null +++ b/web/src/lib/api/schema.d.ts @@ -0,0 +1,1614 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/v1/auth/jwks": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["AuthService_GetJwks"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/auth/login": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["AuthService_LoginPassword"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/auth/password": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["AuthService_SetPassword"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/auth/service": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * View information about the service. + * @description buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + get: operations["AuthService_ServiceInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/order/list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get a list of a customer's orders. + * If accessed through the gateway - shows the current user's orders. */ + get: operations["OrderService_ViewOrders"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/order/orders/{orderId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["OrderService_ViewOrder"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/order/place": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["OrderService_PlaceOrder"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/order/service": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * View information about the service. + * @description buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + get: operations["OrderService_ServiceInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/payment/balance/{customerId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["PaymentService_ViewBalance"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/payment/service": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * View information about the service. + * @description buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + get: operations["PaymentService_ServiceInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/payment/transaction/{transactionId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["PaymentService_ViewTransaction"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/product/list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["ProductService_ViewProducts"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/product/service": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * View information about the service. + * @description buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + get: operations["ProductService_ServiceInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/product/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["ProductService_ViewProduct"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/shipping/service": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * View information about the service. + * @description buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + get: operations["ShippingService_ServiceInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/shipping/shipment/{shipmentId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["ShippingService_ViewShipment"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/shipping/shipment/{shipmentId}/manifest": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["ShippingService_ViewShipmentManifest"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/user/register": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["UserService_RegisterUser"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/user/service": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * View information about the service. + * @description buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + get: operations["UserService_ServiceInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/user/users/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["UserService_ViewUser"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/warehouse/product/{productId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["WarehouseService_ViewProductStock"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/warehouse/reservation/{reservationId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["WarehouseService_ViewReservation"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/warehouse/service": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * View information about the service. + * @description buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + get: operations["WarehouseService_ServiceInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + /** @example { + * "@type": "@type" + * } */ + protobufAny: { + "@type"?: string; + } & { + [key: string]: Record; + }; + /** @example { + * "code": 0, + * "details": [ + * { + * "@type": "@type" + * }, + * { + * "@type": "@type" + * } + * ], + * "message": "message" + * } */ + rpcStatus: { + /** Format: int32 */ + code?: number; + message?: string; + details?: components["schemas"]["protobufAny"][]; + }; + /** @example { + * "expiresIn": "expiresIn", + * "tokenType": "tokenType", + * "accessToken": "accessToken" + * } */ + v1AuthToken: { + tokenType?: string; + accessToken?: string; + /** Format: int64 */ + expiresIn?: string; + }; + /** @example { + * "balance": 0.8008282, + * "customerId": "customerId" + * } */ + v1CustomerBalance: { + customerId?: string; + /** Format: float */ + balance?: number; + }; + /** @example { + * "keys": [ + * { + * "kty": "kty", + * "use": "use", + * "crv": "crv", + * "x": "x", + * "y": "y", + * "alg": "alg" + * }, + * { + * "kty": "kty", + * "use": "use", + * "crv": "crv", + * "x": "x", + * "y": "y", + * "alg": "alg" + * } + * ] + * } */ + v1GetJwksResponse: { + keys?: components["schemas"]["v1PublicEcJWK"][]; + }; + v1LoginPasswordRequest: { + userId: string; + password: string; + }; + /** @example { + * "data": { + * "expiresIn": "expiresIn", + * "tokenType": "tokenType", + * "accessToken": "accessToken" + * }, + * "detail": "detail" + * } */ + v1LoginPasswordResponse: { + detail?: string; + data?: components["schemas"]["v1AuthToken"]; + }; + /** @example { + * "createdAt": "createdAt", + * "shippingId": "shippingId", + * "customerId": "customerId", + * "id": "id", + * "items": { + * "key": 0 + * }, + * "transactionId": "transactionId", + * "status": "ORDER_STATUS_UNSPECIFIED", + * "updatedAt": "updatedAt" + * } */ + v1Order: { + id?: string; + status?: components["schemas"]["v1OrderStatus"]; + /** @description 'items' consists of a mapping of Product ID to Quantity. */ + items?: { + [key: string]: number; + }; + customerId?: string; + transactionId?: string; + shippingId?: string; + /** Format: int64 */ + createdAt?: string; + /** Format: int64 */ + updatedAt?: string; + }; + /** + * - ORDER_STATUS_PROCESSING: awaiting price quotes for products + * - ORDER_STATUS_PENDING: awaiting stock allocation, shipping allotment and payment + * @default ORDER_STATUS_UNSPECIFIED + * @enum {string} + */ + v1OrderStatus: "ORDER_STATUS_UNSPECIFIED" | "ORDER_STATUS_PROCESSING" | "ORDER_STATUS_PENDING" | "ORDER_STATUS_REJECTED" | "ORDER_STATUS_APPROVED" | "ORDER_STATUS_COMPLETED"; + /** @example { + * "order": { + * "createdAt": "createdAt", + * "shippingId": "shippingId", + * "customerId": "customerId", + * "id": "id", + * "items": { + * "key": 0 + * }, + * "transactionId": "transactionId", + * "status": "ORDER_STATUS_UNSPECIFIED", + * "updatedAt": "updatedAt" + * } + * } */ + v1PlaceOrderResponse: { + order?: components["schemas"]["v1Order"]; + }; + /** @example { + * "createdAt": "createdAt", + * "price": 0.8008282, + * "name": "name", + * "description": "description", + * "id": "id", + * "updatedAt": "updatedAt" + * } */ + v1Product: { + id?: string; + name?: string; + description?: string; + /** Format: float */ + price?: number; + /** Format: int64 */ + createdAt?: string; + /** Format: int64 */ + updatedAt?: string; + }; + /** @example { + * "quantity": 0, + * "productId": "productId" + * } */ + v1ProductStock: { + productId?: string; + /** Format: int32 */ + quantity?: number; + }; + /** @example { + * "kty": "kty", + * "use": "use", + * "crv": "crv", + * "x": "x", + * "y": "y", + * "alg": "alg" + * } */ + v1PublicEcJWK: { + kty?: string; + use?: string; + alg?: string; + crv?: string; + x?: string; + y?: string; + }; + /** @example { + * "user": { + * "firstName": "firstName", + * "lastName": "lastName", + * "createdAt": "createdAt", + * "id": "id", + * "email": "email", + * "updatedAt": "updatedAt" + * } + * } */ + v1RegisterUserResponse: { + user?: components["schemas"]["v1User"]; + }; + /** @example { + * "createdAt": "createdAt", + * "orderId": "orderId", + * "reservedStock": [ + * { + * "quantity": 0, + * "productId": "productId" + * }, + * { + * "quantity": 0, + * "productId": "productId" + * } + * ], + * "id": "id" + * } */ + v1Reservation: { + id?: string; + orderId?: string; + reservedStock?: components["schemas"]["v1ReservationStock"][]; + /** Format: int64 */ + createdAt?: string; + }; + /** @example { + * "quantity": 0, + * "productId": "productId" + * } */ + v1ReservationStock: { + productId?: string; + /** Format: int32 */ + quantity?: number; + }; + /** @example { + * "sourceLicense": "sourceLicense", + * "name": "name", + * "source": "source" + * } */ + v1ServiceInfoResponse: { + name?: string; + source?: string; + sourceLicense?: string; + }; + v1SetPasswordRequest: { + userId: string; + password: string; + }; + /** @example { + * "detail": "detail" + * } */ + v1SetPasswordResponse: { + detail?: string; + }; + /** @example { + * "createdAt": "createdAt", + * "dispatched": true, + * "orderId": "orderId", + * "id": "id", + * "updatedAt": "updatedAt" + * } */ + v1Shipment: { + id?: string; + orderId?: string; + dispatched?: boolean; + /** Format: int64 */ + createdAt?: string; + /** Format: int64 */ + updatedAt?: string; + }; + /** @example { + * "quantity": 0, + * "productId": "productId", + * "shipmentId": "shipmentId" + * } */ + v1ShipmentItem: { + shipmentId?: string; + productId?: string; + /** Format: int32 */ + quantity?: number; + }; + /** @example { + * "amount": 0.8008282, + * "orderId": "orderId", + * "reversedAt": "reversedAt", + * "customerId": "customerId", + * "processedAt": "processedAt", + * "id": "id" + * } */ + v1Transaction: { + id?: string; + /** Format: float */ + amount?: number; + orderId?: string; + customerId?: string; + /** + * Format: int64 + * @description Optional - If set, then the transaction has been refunded. + */ + reversedAt?: string; + /** Format: int64 */ + processedAt?: string; + }; + /** @example { + * "firstName": "firstName", + * "lastName": "lastName", + * "createdAt": "createdAt", + * "id": "id", + * "email": "email", + * "updatedAt": "updatedAt" + * } */ + v1User: { + id?: string; + email?: string; + firstName?: string; + lastName?: string; + /** Format: int64 */ + createdAt?: string; + /** Format: int64 */ + updatedAt?: string; + }; + /** @example { + * "balance": { + * "balance": 0.8008282, + * "customerId": "customerId" + * } + * } */ + v1ViewBalanceResponse: { + balance?: components["schemas"]["v1CustomerBalance"]; + }; + /** @example { + * "order": { + * "createdAt": "createdAt", + * "shippingId": "shippingId", + * "customerId": "customerId", + * "id": "id", + * "items": { + * "key": 0 + * }, + * "transactionId": "transactionId", + * "status": "ORDER_STATUS_UNSPECIFIED", + * "updatedAt": "updatedAt" + * } + * } */ + v1ViewOrderResponse: { + order?: components["schemas"]["v1Order"]; + }; + /** @example { + * "orders": [ + * { + * "createdAt": "createdAt", + * "shippingId": "shippingId", + * "customerId": "customerId", + * "id": "id", + * "items": { + * "key": 0 + * }, + * "transactionId": "transactionId", + * "status": "ORDER_STATUS_UNSPECIFIED", + * "updatedAt": "updatedAt" + * }, + * { + * "createdAt": "createdAt", + * "shippingId": "shippingId", + * "customerId": "customerId", + * "id": "id", + * "items": { + * "key": 0 + * }, + * "transactionId": "transactionId", + * "status": "ORDER_STATUS_UNSPECIFIED", + * "updatedAt": "updatedAt" + * } + * ] + * } */ + v1ViewOrdersResponse: { + orders?: components["schemas"]["v1Order"][]; + }; + /** @example { + * "product": { + * "createdAt": "createdAt", + * "price": 0.8008282, + * "name": "name", + * "description": "description", + * "id": "id", + * "updatedAt": "updatedAt" + * } + * } */ + v1ViewProductResponse: { + product?: components["schemas"]["v1Product"]; + }; + /** @example { + * "stock": { + * "quantity": 0, + * "productId": "productId" + * } + * } */ + v1ViewProductStockResponse: { + stock?: components["schemas"]["v1ProductStock"]; + }; + /** @example { + * "products": [ + * { + * "createdAt": "createdAt", + * "price": 0.8008282, + * "name": "name", + * "description": "description", + * "id": "id", + * "updatedAt": "updatedAt" + * }, + * { + * "createdAt": "createdAt", + * "price": 0.8008282, + * "name": "name", + * "description": "description", + * "id": "id", + * "updatedAt": "updatedAt" + * } + * ] + * } */ + v1ViewProductsResponse: { + products?: components["schemas"]["v1Product"][]; + }; + /** @example { + * "reservation": { + * "createdAt": "createdAt", + * "orderId": "orderId", + * "reservedStock": [ + * { + * "quantity": 0, + * "productId": "productId" + * }, + * { + * "quantity": 0, + * "productId": "productId" + * } + * ], + * "id": "id" + * } + * } */ + v1ViewReservationResponse: { + reservation?: components["schemas"]["v1Reservation"]; + }; + /** @example { + * "manifest": [ + * { + * "quantity": 0, + * "productId": "productId", + * "shipmentId": "shipmentId" + * }, + * { + * "quantity": 0, + * "productId": "productId", + * "shipmentId": "shipmentId" + * } + * ] + * } */ + v1ViewShipmentManifestResponse: { + manifest?: components["schemas"]["v1ShipmentItem"][]; + }; + /** @example { + * "shipment": { + * "createdAt": "createdAt", + * "dispatched": true, + * "orderId": "orderId", + * "id": "id", + * "updatedAt": "updatedAt" + * } + * } */ + v1ViewShipmentResponse: { + shipment?: components["schemas"]["v1Shipment"]; + }; + /** @example { + * "transaction": { + * "amount": 0.8008282, + * "orderId": "orderId", + * "reversedAt": "reversedAt", + * "customerId": "customerId", + * "processedAt": "processedAt", + * "id": "id" + * } + * } */ + v1ViewTransactionResponse: { + transaction?: components["schemas"]["v1Transaction"]; + }; + /** @example { + * "user": { + * "firstName": "firstName", + * "lastName": "lastName", + * "createdAt": "createdAt", + * "id": "id", + * "email": "email", + * "updatedAt": "updatedAt" + * } + * } */ + v1ViewUserResponse: { + user?: components["schemas"]["v1User"]; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + AuthService_GetJwks: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1GetJwksResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + AuthService_LoginPassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["v1LoginPasswordRequest"]; + }; + }; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1LoginPasswordResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + AuthService_SetPassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["v1SetPasswordRequest"]; + }; + }; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1SetPasswordResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + AuthService_ServiceInfo: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ServiceInfoResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + OrderService_ViewOrders: { + parameters: { + query?: { + customerId?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewOrdersResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + OrderService_ViewOrder: { + parameters: { + query?: never; + header?: never; + path: { + orderId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewOrderResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + OrderService_PlaceOrder: { + parameters: { + query?: { + customerId?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + [key: string]: number; + }; + }; + }; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1PlaceOrderResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + OrderService_ServiceInfo: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ServiceInfoResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + PaymentService_ViewBalance: { + parameters: { + query?: never; + header?: never; + path: { + customerId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewBalanceResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + PaymentService_ServiceInfo: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ServiceInfoResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + PaymentService_ViewTransaction: { + parameters: { + query?: never; + header?: never; + path: { + transactionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewTransactionResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + ProductService_ViewProducts: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewProductsResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + ProductService_ServiceInfo: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ServiceInfoResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + ProductService_ViewProduct: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewProductResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + ShippingService_ServiceInfo: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ServiceInfoResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + ShippingService_ViewShipment: { + parameters: { + query?: never; + header?: never; + path: { + shipmentId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewShipmentResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + ShippingService_ViewShipmentManifest: { + parameters: { + query?: never; + header?: never; + path: { + shipmentId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewShipmentManifestResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + UserService_RegisterUser: { + parameters: { + query: { + firstName: string; + lastName: string; + email: string; + password: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1RegisterUserResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + UserService_ServiceInfo: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ServiceInfoResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + UserService_ViewUser: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewUserResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + WarehouseService_ViewProductStock: { + parameters: { + query?: never; + header?: never; + path: { + productId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewProductStockResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + WarehouseService_ViewReservation: { + parameters: { + query?: never; + header?: never; + path: { + reservationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ViewReservationResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; + WarehouseService_ServiceInfo: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A successful response. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["v1ServiceInfoResponse"]; + }; + }; + /** @description An unexpected error response. */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["rpcStatus"]; + }; + }; + }; + }; +} diff --git a/web/src/lib/config.ts b/web/src/lib/config.ts new file mode 100644 index 0000000..224dd10 --- /dev/null +++ b/web/src/lib/config.ts @@ -0,0 +1,3 @@ +import { PUBLIC_API_URL } from "$env/static/public"; + +export const API_URL = PUBLIC_API_URL || "http://localhost:80/v1/"; \ No newline at end of file diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index cc88df0..5f3bb7b 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -1,2 +1,98 @@ -

Welcome to SvelteKit

-

Visit svelte.dev/docs/kit to read the documentation

+ + +
+ +
+
+
+ + + Stocklet + + + + + + + +
+
+
+ + +
+
+
+
+

+ Phasellus ut pulvinar nisl. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer dignissim odio orci, in volutpat nunc lacinia et. Phasellus ut dictum nibh. Donec hendrerit nunc sed elit porttitor, in efficitur arcu hendrerit. + Aenean erat est, maximus id congue ut, venenatis eu nibh. Vivamus vitae varius erat, eu tempor urna. Aenean viverra sed erat sed viverra. Fusce vulputate, mauris eget hendrerit venenatis, eros felis rutrum orci, in commodo mauris elit sit amet arcu. +

+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+

Loved by providers

+

+ Providers use Stocklet to sell their products with confidence. +

+
+
+
“Vivamus sit amet est eu urna lobortis cursus sed at odio.”
+
+ +
+
John Doe
+
CEO, Acme Inc.
+
+ +
+
+
+
“Aliquam velit augue, varius quis est ac, interdum tincidunt lorem.”
+
+ +
+
Jane Doe
+
Product Lead, Wayne Industries.
+
+ +
+
+
+
“Aliquam a lobortis nisi. Nullam varius a diam nec vulputate.”
+
+ +
+
Alice Wonderland
+
Managing Directory, E Corp.
+
+ +
+
+
+
+
+ +
+
diff --git a/web/src/stores/theme.ts b/web/src/stores/theme.ts new file mode 100644 index 0000000..08434ec --- /dev/null +++ b/web/src/stores/theme.ts @@ -0,0 +1,35 @@ +import { writable } from 'svelte/store'; + +function getInitialDark(): boolean { + if (typeof window === 'undefined') return false; + try { + const saved = localStorage.getItem('color-scheme'); + if (saved === 'dark') return true; + if (saved === 'light') return false; + return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + } catch { + return false; + } +} + +export const darkMode = writable(getInitialDark()); + +export function setDarkMode(value: boolean): void { + darkMode.set(value); +} + +export function toggleDarkMode(): void { + darkMode.update((v) => !v); +} + +if (typeof window !== 'undefined') { + darkMode.subscribe((isDark) => { + const root = document.documentElement; + root.classList.toggle('dark', isDark); + try { + localStorage.setItem('color-scheme', isDark ? 'dark' : 'light'); + } catch { + // ignore storage write errors + } + }); +} \ No newline at end of file