From 7827a43ffcfd6aac61fcb3c5dfa33a4e067b4204 Mon Sep 17 00:00:00 2001 From: Zuri Klaschka Date: Fri, 12 Jan 2024 18:37:42 +0100 Subject: [PATCH] Use submodules instead of exported namespaces in `@wuespace/telestion` Previously, anything that wasn't exported on the root level of the `@wuespace/telestion` library had to be imported indirectly through namespaces: ```ts import { utils } from '@wuespace/telestion'; const { wait } = utils; ``` This didn't provide a great developer experience, as imports couldn't be reoslved automatically. Instead, these features now must be imported using submodules / path imports: ```ts import { wait } from '@wuespace/telestion/utils'; ``` As of the time of this change, a total of six of these modules exist: - `@wuespace/telestion/application`, corresponding to `import { application } from '@wuespace/telestion'` - `@wuespace/telestion/auth`, corresponding to `import { auth } from '@wuespace/telestion'` - `@wuespace/telestion/nats`, corresponding to `import { nats } from '@wuespace/telestion'` - `@wuespace/telestion/user-data`, corresponding to `import { userData } from '@wuespace/telestion'` - `@wuespace/telestion/utils`, corresponding to `import { utils } from '@wuespace/telestion'` - `@wuespace/telestion/widget`, corresponding to `import { widget } from '@wuespace/telestion'` The previous namespaces were removed. --- frontend-react/.eslintrc.cjs | 8 +- frontend-react/package.json | 38 +++- frontend-react/pnpm-lock.yaml | 197 ++++++++++++++++++ frontend-react/src/app/index.tsx | 2 +- frontend-react/src/lib/application/index.tsx | 17 ++ .../routes/dashboard-editor/routing.ts | 2 +- .../routes/dashboard-index/routing.ts | 2 +- .../routes/dashboard-page/routing.ts | 2 +- .../src/lib/application/routes/dashboard.ts | 2 +- .../lib/application/routes/login/routing.ts | 2 +- .../src/lib/application/routes/logout.ts | 2 +- .../application/routes/migration/routing.ts | 2 +- .../src/lib/application/routes/root.ts | 2 +- frontend-react/src/lib/auth/index.ts | 13 ++ frontend-react/src/lib/index.ts | 7 - frontend-react/src/lib/mod-application.ts | 2 + frontend-react/src/lib/mod-auth.ts | 2 + frontend-react/src/lib/mod-nats.ts | 2 + frontend-react/src/lib/mod-user-data.ts | 2 + frontend-react/src/lib/mod-utils.ts | 2 + frontend-react/src/lib/mod-widget.ts | 2 + frontend-react/src/lib/nats/index.ts | 14 +- frontend-react/src/lib/user-data/index.ts | 10 + frontend-react/src/lib/user-data/model.ts | 2 +- frontend-react/src/lib/utils.ts | 66 ------ frontend-react/src/lib/utils/file-utils.ts | 32 +++ frontend-react/src/lib/utils/index.ts | 13 ++ frontend-react/src/lib/utils/promise-utils.ts | 10 + .../src/lib/utils/user-data-utils.ts | 22 ++ frontend-react/src/lib/widget/index.ts | 10 + frontend-react/tsconfig.json | 6 +- frontend-react/typedoc.json | 10 +- frontend-react/vite.config.ts | 20 +- 33 files changed, 432 insertions(+), 93 deletions(-) create mode 100644 frontend-react/src/lib/mod-application.ts create mode 100644 frontend-react/src/lib/mod-auth.ts create mode 100644 frontend-react/src/lib/mod-nats.ts create mode 100644 frontend-react/src/lib/mod-user-data.ts create mode 100644 frontend-react/src/lib/mod-utils.ts create mode 100644 frontend-react/src/lib/mod-widget.ts delete mode 100644 frontend-react/src/lib/utils.ts create mode 100644 frontend-react/src/lib/utils/file-utils.ts create mode 100644 frontend-react/src/lib/utils/index.ts create mode 100644 frontend-react/src/lib/utils/promise-utils.ts create mode 100644 frontend-react/src/lib/utils/user-data-utils.ts diff --git a/frontend-react/.eslintrc.cjs b/frontend-react/.eslintrc.cjs index 0da57819..29578c28 100644 --- a/frontend-react/.eslintrc.cjs +++ b/frontend-react/.eslintrc.cjs @@ -38,6 +38,12 @@ module.exports = { 'tsdoc/syntax': 'warn' }, settings: { - react: { version: 'detect' } + react: { version: 'detect' }, + // Support import aliases + 'import/resolver': { + typescript: { + projects: ['./tsconfig.json', './tsconfig.node.json'] + } + } } }; diff --git a/frontend-react/package.json b/frontend-react/package.json index 4f8a0d66..64810652 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -35,11 +35,42 @@ "dist", "types" ], - "main": "./dist/telestion.umd.cjs", + "main": "./dist/index.cjs", "exports": { ".": { - "import": "./dist/telestion.js", - "require": "./dist/telestion.umd.cjs" + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "types": "./types/src/lib/index.d.ts" + }, + "./application": { + "import": "./dist/mod-application.js", + "require": "./dist/mod-application.cjs", + "types": "./types/src/lib/mod-application.d.ts" + }, + "./auth": { + "import": "./dist/mod-auth.js", + "require": "./dist/mod-auth.cjs", + "types": "./types/src/lib/mod-auth.d.ts" + }, + "./nats": { + "import": "./dist/mod-nats.js", + "require": "./dist/mod-nats.cjs", + "types": "./types/src/lib/mod-nats.d.ts" + }, + "./user-data": { + "import": "./dist/mod-user-data.js", + "require": "./dist/mod-user-data.cjs", + "types": "./types/src/lib/mod-user-data.d.ts" + }, + "./utils": { + "import": "./dist/mod-utils.js", + "require": "./dist/mod-utils.cjs", + "types": "./types/src/lib/mod-utils.d.ts" + }, + "./widget": { + "import": "./dist/mod-widget.js", + "require": "./dist/mod-widget.cjs", + "types": "./types/src/lib/mod-widget.d.ts" }, "./telestion.css": "./dist/style.css" }, @@ -86,6 +117,7 @@ "@vitest/ui": "^1.0.4", "eslint": "^8.53.0", "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", diff --git a/frontend-react/pnpm-lock.yaml b/frontend-react/pnpm-lock.yaml index beb9728d..52151412 100644 --- a/frontend-react/pnpm-lock.yaml +++ b/frontend-react/pnpm-lock.yaml @@ -67,6 +67,9 @@ devDependencies: eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@8.54.0) + eslint-import-resolver-typescript: + specifier: ^3.6.1 + version: 3.6.1(@typescript-eslint/parser@6.11.0)(eslint-plugin-import@2.29.1)(eslint@8.54.0) eslint-plugin-jsx-a11y: specifier: ^6.8.0 version: 6.8.0(eslint@8.54.0) @@ -918,6 +921,10 @@ packages: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + /@types/node@20.10.4: resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} dependencies: @@ -1284,6 +1291,17 @@ packages: engines: {node: '>=8'} dev: true + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} @@ -1597,6 +1615,17 @@ packages: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -1716,6 +1745,14 @@ packages: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /enhanced-resolve@5.15.0: + resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + dev: true + /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -1870,6 +1907,104 @@ packages: eslint: 8.54.0 dev: true + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.13.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.11.0)(eslint-plugin-import@2.29.1)(eslint@8.54.0): + resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + dependencies: + debug: 4.3.4(supports-color@8.1.1) + enhanced-resolve: 5.15.0 + eslint: 8.54.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.11.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.11.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0) + fast-glob: 3.3.2 + get-tsconfig: 4.7.2 + is-core-module: 2.13.1 + is-glob: 4.0.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.11.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 6.11.0(eslint@8.54.0)(typescript@5.2.2) + debug: 3.2.7 + eslint: 8.54.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.11.0)(eslint-plugin-import@2.29.1)(eslint@8.54.0) + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 6.11.0(eslint@8.54.0)(typescript@5.2.2) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.54.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.11.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0) + hasown: 2.0.0 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + /eslint-plugin-jsx-a11y@6.8.0(eslint@8.54.0): resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} engines: {node: '>=4.0'} @@ -2270,6 +2405,12 @@ packages: get-intrinsic: 1.2.2 dev: true + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2346,6 +2487,10 @@ packages: get-intrinsic: 1.2.2 dev: true + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true @@ -2768,6 +2913,13 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} dev: true @@ -2939,6 +3091,10 @@ packages: brace-expansion: 2.0.1 dev: true + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + /minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} @@ -3077,6 +3233,15 @@ packages: es-abstract: 1.22.3 dev: true + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + dev: true + /object.hasown@1.1.3: resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} dependencies: @@ -3512,6 +3677,10 @@ packages: engines: {node: '>=8'} dev: true + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve-pkg@2.0.0: resolution: {integrity: sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==} engines: {node: '>=8'} @@ -3526,6 +3695,15 @@ packages: path-parse: 1.0.7 dev: true + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true @@ -3850,6 +4028,11 @@ packages: ansi-regex: 6.0.1 dev: true + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + /strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -3905,6 +4088,11 @@ packages: tslib: 2.6.2 dev: true + /tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + dev: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -3977,6 +4165,15 @@ packages: typescript: 5.2.2 dev: true + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} diff --git a/frontend-react/src/app/index.tsx b/frontend-react/src/app/index.tsx index 3f1d2716..c9cfcb05 100644 --- a/frontend-react/src/app/index.tsx +++ b/frontend-react/src/app/index.tsx @@ -1,4 +1,4 @@ -import { initTelestion, registerWidgets, UserData } from '../lib'; +import { initTelestion, registerWidgets, UserData } from '@wuespace/telestion'; import { simpleWidget } from './widgets/simple-widget'; import { errorWidget } from './widgets/error-widget'; diff --git a/frontend-react/src/lib/application/index.tsx b/frontend-react/src/lib/application/index.tsx index 21524773..a266c817 100644 --- a/frontend-react/src/lib/application/index.tsx +++ b/frontend-react/src/lib/application/index.tsx @@ -1,3 +1,20 @@ +/** + * @packageDocumentation + * + * This package provides the main entry point for the Telestion frontend application. + * + * You can initialize the application by calling the {@link initTelestion} function. + * + * @example + * ```ts + * import { initTelestion } from '@wuespace/telestion/application'; + * // or, for convenience: + * // import { initTelestion } from '@wuespace/telestion'; + * + * initTelestion({ ... }); + * ``` + */ + // Import styles first to allow overriding bootstrap styles in CSS modules import 'bootstrap-icons/font/bootstrap-icons.min.css'; import './index.scss'; diff --git a/frontend-react/src/lib/application/routes/dashboard-editor/routing.ts b/frontend-react/src/lib/application/routes/dashboard-editor/routing.ts index 7de3eeb1..3badf980 100644 --- a/frontend-react/src/lib/application/routes/dashboard-editor/routing.ts +++ b/frontend-react/src/lib/application/routes/dashboard-editor/routing.ts @@ -11,7 +11,7 @@ import { setUserData, UserData } from '../../../user-data'; -import { isUserDataUpToDate } from '../../../utils.ts'; +import { isUserDataUpToDate } from '../../../utils'; import { TelestionOptions } from '../../model.ts'; import { setResumeAfterLogin } from '../login'; diff --git a/frontend-react/src/lib/application/routes/dashboard-index/routing.ts b/frontend-react/src/lib/application/routes/dashboard-index/routing.ts index 967f6f36..673e019d 100644 --- a/frontend-react/src/lib/application/routes/dashboard-index/routing.ts +++ b/frontend-react/src/lib/application/routes/dashboard-index/routing.ts @@ -1,7 +1,7 @@ import { isLoggedIn } from '../../../auth'; import { generatePath, redirect } from 'react-router-dom'; import { getUserData } from '../../../user-data'; -import { isUserDataUpToDate } from '../../../utils.ts'; +import { isUserDataUpToDate } from '../../../utils'; import { TelestionOptions } from '../../model.ts'; export function dashboardIndexLoader({ version }: TelestionOptions) { diff --git a/frontend-react/src/lib/application/routes/dashboard-page/routing.ts b/frontend-react/src/lib/application/routes/dashboard-page/routing.ts index 60c837fc..ea2b0056 100644 --- a/frontend-react/src/lib/application/routes/dashboard-page/routing.ts +++ b/frontend-react/src/lib/application/routes/dashboard-page/routing.ts @@ -8,7 +8,7 @@ import { import { TelestionOptions } from '../../model.ts'; import { isLoggedIn } from '../../../auth'; import { getUserData, setUserData, UserData } from '../../../user-data'; -import { isUserDataUpToDate } from '../../../utils.ts'; +import { isUserDataUpToDate } from '../../../utils'; import { dashboardCreateAction } from '../dashboard.ts'; import { setResumeAfterLogin } from '../login'; diff --git a/frontend-react/src/lib/application/routes/dashboard.ts b/frontend-react/src/lib/application/routes/dashboard.ts index 037a1951..baf820b8 100644 --- a/frontend-react/src/lib/application/routes/dashboard.ts +++ b/frontend-react/src/lib/application/routes/dashboard.ts @@ -2,7 +2,7 @@ import { TelestionOptions } from '../model.ts'; import { isLoggedIn } from '../../auth'; import { generatePath, redirect } from 'react-router-dom'; import { getEmptyDashboard, getUserData, setUserData } from '../../user-data'; -import { isUserDataUpToDate } from '../../utils.ts'; +import { isUserDataUpToDate } from '../../utils'; export function dashboardCreateAction({ version }: TelestionOptions) { return () => { diff --git a/frontend-react/src/lib/application/routes/login/routing.ts b/frontend-react/src/lib/application/routes/login/routing.ts index 1191c2bf..7a0be9c0 100644 --- a/frontend-react/src/lib/application/routes/login/routing.ts +++ b/frontend-react/src/lib/application/routes/login/routing.ts @@ -1,7 +1,7 @@ import { ActionFunctionArgs, redirect } from 'react-router-dom'; import { attemptAutoLogin, isLoggedIn, login, LoginError } from '../../../auth'; import { TelestionOptions } from '../../model.ts'; -import { wait } from '../../../utils.ts'; +import { wait } from '../../../utils'; let resumeAfterLogin: string | undefined = undefined; diff --git a/frontend-react/src/lib/application/routes/logout.ts b/frontend-react/src/lib/application/routes/logout.ts index 43519043..0ca92731 100644 --- a/frontend-react/src/lib/application/routes/logout.ts +++ b/frontend-react/src/lib/application/routes/logout.ts @@ -1,6 +1,6 @@ import { redirect } from 'react-router-dom'; import { isLoggedIn, logout } from '../../auth'; -import { wait } from '../../utils.ts'; +import { wait } from '../../utils'; import { resetResumeAfterLogin } from './login'; export function logoutLoader() { diff --git a/frontend-react/src/lib/application/routes/migration/routing.ts b/frontend-react/src/lib/application/routes/migration/routing.ts index 3c656962..3498030c 100644 --- a/frontend-react/src/lib/application/routes/migration/routing.ts +++ b/frontend-react/src/lib/application/routes/migration/routing.ts @@ -1,7 +1,7 @@ import { ActionFunctionArgs, redirect } from 'react-router-dom'; import { isLoggedIn } from '../../../auth'; -import { isUserDataUpToDate, loadFileContents } from '../../../utils.ts'; +import { isUserDataUpToDate, loadFileContents } from '../../../utils'; import { getBlankUserData, getUserData, diff --git a/frontend-react/src/lib/application/routes/root.ts b/frontend-react/src/lib/application/routes/root.ts index 1801d7c6..5b15b48d 100644 --- a/frontend-react/src/lib/application/routes/root.ts +++ b/frontend-react/src/lib/application/routes/root.ts @@ -2,7 +2,7 @@ import { redirect } from 'react-router-dom'; import { isLoggedIn } from '../../auth'; import { getUserData } from '../../user-data'; -import { isUserDataUpToDate } from '../../utils.ts'; +import { isUserDataUpToDate } from '../../utils'; import { TelestionOptions } from '../model.ts'; export function rootLoader({ version }: TelestionOptions) { diff --git a/frontend-react/src/lib/auth/index.ts b/frontend-react/src/lib/auth/index.ts index cb04fd2b..cd14097c 100644 --- a/frontend-react/src/lib/auth/index.ts +++ b/frontend-react/src/lib/auth/index.ts @@ -1,3 +1,16 @@ +/** + * @packageDocumentation + * + * Functions and types relating to the authentication of users in the Telestion frontend. + * + * Note that in most cases, you don't need to import anything from this package directly, since auth*n is already + * handled by the framework itself. + * + * @example + * ```tsx + * import { ... } from '@wuespace/telestion/auth'; + * ``` + */ export * from './model.ts'; export * from './state.ts'; export * from './controller.ts'; diff --git a/frontend-react/src/lib/index.ts b/frontend-react/src/lib/index.ts index 6c0792b8..de9053f0 100644 --- a/frontend-react/src/lib/index.ts +++ b/frontend-react/src/lib/index.ts @@ -22,13 +22,6 @@ * @see {@link initTelestion} */ -export * as application from './application'; -export * as auth from './auth'; -export * as userData from './user-data'; -export * as widget from './widget'; -export * as utils from './utils.ts'; -export * as nats from './nats'; - // application export { initTelestion, useWidgetConfig } from './application'; export type { TelestionOptions } from './application'; diff --git a/frontend-react/src/lib/mod-application.ts b/frontend-react/src/lib/mod-application.ts new file mode 100644 index 00000000..ca265535 --- /dev/null +++ b/frontend-react/src/lib/mod-application.ts @@ -0,0 +1,2 @@ +// Separate file to generate the correct output file name in the dist folder +export * from './application'; diff --git a/frontend-react/src/lib/mod-auth.ts b/frontend-react/src/lib/mod-auth.ts new file mode 100644 index 00000000..adc05fec --- /dev/null +++ b/frontend-react/src/lib/mod-auth.ts @@ -0,0 +1,2 @@ +// Separate file to generate the correct output file name in the dist folder +export * from './auth'; diff --git a/frontend-react/src/lib/mod-nats.ts b/frontend-react/src/lib/mod-nats.ts new file mode 100644 index 00000000..d323bfd1 --- /dev/null +++ b/frontend-react/src/lib/mod-nats.ts @@ -0,0 +1,2 @@ +// Separate file to generate the correct output file name in the dist folder +export * from './nats'; diff --git a/frontend-react/src/lib/mod-user-data.ts b/frontend-react/src/lib/mod-user-data.ts new file mode 100644 index 00000000..78294ff3 --- /dev/null +++ b/frontend-react/src/lib/mod-user-data.ts @@ -0,0 +1,2 @@ +// Separate file to generate the correct output file name in the dist folder +export * from './user-data'; diff --git a/frontend-react/src/lib/mod-utils.ts b/frontend-react/src/lib/mod-utils.ts new file mode 100644 index 00000000..5655d085 --- /dev/null +++ b/frontend-react/src/lib/mod-utils.ts @@ -0,0 +1,2 @@ +// Separate file to generate the correct output file name in the dist folder +export * from './utils'; diff --git a/frontend-react/src/lib/mod-widget.ts b/frontend-react/src/lib/mod-widget.ts new file mode 100644 index 00000000..05705a70 --- /dev/null +++ b/frontend-react/src/lib/mod-widget.ts @@ -0,0 +1,2 @@ +// Separate file to generate the correct output file name in the dist folder +export * from './widget'; diff --git a/frontend-react/src/lib/nats/index.ts b/frontend-react/src/lib/nats/index.ts index eaa20439..edcf0aa3 100644 --- a/frontend-react/src/lib/nats/index.ts +++ b/frontend-react/src/lib/nats/index.ts @@ -1,4 +1,16 @@ -// re-export NATS utils (for convenience) +/** + * @packageDocumentation + * + * Re-exporting the most used types and functions from the `nats.ws` package. + * + * @example + * ```tsx + * import { Msg, JSONCodec, ... } from '@wuespace/telestion/nats'; + * ``` + * + * @see https://docs.nats.io/using-nats/developer + * @see https://github.com/nats-io/nats.ws#readme + */ export { JSONCodec, StringCodec, headers } from 'nats.ws'; export type { NatsError, diff --git a/frontend-react/src/lib/user-data/index.ts b/frontend-react/src/lib/user-data/index.ts index cde7e438..7df9bf34 100644 --- a/frontend-react/src/lib/user-data/index.ts +++ b/frontend-react/src/lib/user-data/index.ts @@ -1,2 +1,12 @@ +/** + * @packageDocumentation + * + * Types and utilities for interacting with the user data stored on the user's device. + * + * @example + * ```tsx + * import { ... } from '@wuespace/telestion/user-data'; + * ``` + */ export * from './model.ts'; export * from './state.ts'; diff --git a/frontend-react/src/lib/user-data/model.ts b/frontend-react/src/lib/user-data/model.ts index 1fa61a74..7a280c57 100644 --- a/frontend-react/src/lib/user-data/model.ts +++ b/frontend-react/src/lib/user-data/model.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { generateDashboardId } from '../utils.ts'; +import { generateDashboardId } from '../utils'; /** * A regular expression that matches semantic version numbers. diff --git a/frontend-react/src/lib/utils.ts b/frontend-react/src/lib/utils.ts deleted file mode 100644 index d6a345d0..00000000 --- a/frontend-react/src/lib/utils.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { UserData } from './user-data'; - -/** - * Waits for the specified amount of time before resolving the returned promise. - * - * @param timeout - The duration in milliseconds to wait before resolving. - * @returns A promise that resolves after the specified time has elapsed. - * @internal - */ -export function wait(timeout: number): Promise { - return new Promise(resolve => setTimeout(resolve, timeout)); -} - -/** - * Generates a unique identifier for a dashboard. - * - * @returns The generated dashboard identifier. - */ -export function generateDashboardId(): string { - return Math.floor(Date.now()).toString(32); -} - -/** - * Checks if the user data is up-to-date with the current version of the application. - * @param userData - the user data to compare with the application version - * @param currentVersion - the current version of the application - */ -export function isUserDataUpToDate( - userData: UserData | undefined, - currentVersion: string -) { - return !!userData && userData.version === currentVersion; -} - -/** - * Loads the contents of a specified file. - * - * @param file - The file object to load contents from. - * @param encoding - The encoding to use while reading the file. Default is UTF-8. - * - * @returns - A Promise that resolves with the contents of the file as a string. - * - If the file is empty, the Promise will be rejected with an error. - */ -export function loadFileContents( - file: File, - encoding = 'utf-8' -): Promise { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.addEventListener('load', () => { - if (reader.result) { - if (typeof reader.result !== 'string') - // ArrayBuffer - return resolve(new TextDecoder(encoding).decode(reader.result)); - - resolve(reader.result.toString()); - } else { - reject( - new Error('Empty file specified. Please select a non-empty file.') - ); - } - }); - reader.addEventListener('error', reject); - reader.readAsText(file, encoding); - }); -} diff --git a/frontend-react/src/lib/utils/file-utils.ts b/frontend-react/src/lib/utils/file-utils.ts new file mode 100644 index 00000000..572ca4c5 --- /dev/null +++ b/frontend-react/src/lib/utils/file-utils.ts @@ -0,0 +1,32 @@ +/** + * Loads the contents of a specified file. + * + * @param file - The file object to load contents from. + * @param encoding - The encoding to use while reading the file. Default is UTF-8. + * + * @returns - A Promise that resolves with the contents of the file as a string. + * - If the file is empty, the Promise will be rejected with an error. + */ +export function loadFileContents( + file: File, + encoding = 'utf-8' +): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener('load', () => { + if (reader.result) { + if (typeof reader.result !== 'string') + // ArrayBuffer + return resolve(new TextDecoder(encoding).decode(reader.result)); + + resolve(reader.result.toString()); + } else { + reject( + new Error('Empty file specified. Please select a non-empty file.') + ); + } + }); + reader.addEventListener('error', reject); + reader.readAsText(file, encoding); + }); +} diff --git a/frontend-react/src/lib/utils/index.ts b/frontend-react/src/lib/utils/index.ts new file mode 100644 index 00000000..387cff03 --- /dev/null +++ b/frontend-react/src/lib/utils/index.ts @@ -0,0 +1,13 @@ +/** + * @packageDocumentation + * + * Various utility functions around building Telestion frontend apps. + * + * @example + * ```ts + * import { ... } from '@wuespace/telestion/utils'; + * ``` + */ +export * from './promise-utils.ts'; +export * from './user-data-utils.ts'; +export * from './file-utils.ts'; diff --git a/frontend-react/src/lib/utils/promise-utils.ts b/frontend-react/src/lib/utils/promise-utils.ts new file mode 100644 index 00000000..cafe157b --- /dev/null +++ b/frontend-react/src/lib/utils/promise-utils.ts @@ -0,0 +1,10 @@ +/** + * Waits for the specified amount of time before resolving the returned promise. + * + * @param timeout - The duration in milliseconds to wait before resolving. + * @returns A promise that resolves after the specified time has elapsed. + * @internal + */ +export function wait(timeout: number): Promise { + return new Promise(resolve => setTimeout(resolve, timeout)); +} diff --git a/frontend-react/src/lib/utils/user-data-utils.ts b/frontend-react/src/lib/utils/user-data-utils.ts new file mode 100644 index 00000000..916398ee --- /dev/null +++ b/frontend-react/src/lib/utils/user-data-utils.ts @@ -0,0 +1,22 @@ +import { UserData } from '@wuespace/telestion'; + +/** + * Generates a unique identifier for a dashboard. + * + * @returns The generated dashboard identifier. + */ +export function generateDashboardId(): string { + return Math.floor(Date.now()).toString(32); +} + +/** + * Checks if the user data is up-to-date with the current version of the application. + * @param userData - the user data to compare with the application version + * @param currentVersion - the current version of the application + */ +export function isUserDataUpToDate( + userData: UserData | undefined, + currentVersion: string +) { + return !!userData && userData.version === currentVersion; +} diff --git a/frontend-react/src/lib/widget/index.ts b/frontend-react/src/lib/widget/index.ts index efd0035d..83ef0548 100644 --- a/frontend-react/src/lib/widget/index.ts +++ b/frontend-react/src/lib/widget/index.ts @@ -1,3 +1,13 @@ +/** + * @packageDocumentation + * + * Everything you need for building and/or displaying widgets. + * + * @example + * ```tsx + * import { ... } from '@wuespace/telestion/widget'; + * ``` + */ export * from './model.ts'; export * from './state.ts'; export * from './component/widget-renderer.tsx'; diff --git a/frontend-react/tsconfig.json b/frontend-react/tsconfig.json index 8cf20dc3..0b08071f 100644 --- a/frontend-react/tsconfig.json +++ b/frontend-react/tsconfig.json @@ -20,7 +20,11 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "paths": { + "@wuespace/telestion": ["./src/lib"], + "@wuespace/telestion/*": ["./src/lib/*"] + } }, "include": ["src", "features"], "references": [{ "path": "./tsconfig.node.json" }] diff --git a/frontend-react/typedoc.json b/frontend-react/typedoc.json index a2a7e5b2..031b5a87 100644 --- a/frontend-react/typedoc.json +++ b/frontend-react/typedoc.json @@ -6,7 +6,15 @@ "typedoc-plugin-zod" ], "titleLink": "/", - "entryPoints": ["./src/lib/index.ts"], + "entryPoints": [ + "./src/lib", + "./src/lib/application", + "./src/lib/auth", + "./src/lib/nats", + "./src/lib/user-data", + "./src/lib/utils", + "./src/lib/widget" + ], "out": "docs", "githubPages": false, "validation": { diff --git a/frontend-react/vite.config.ts b/frontend-react/vite.config.ts index 098ebe2d..afb54ea7 100644 --- a/frontend-react/vite.config.ts +++ b/frontend-react/vite.config.ts @@ -12,16 +12,25 @@ const bannerText = { description: packageJson.description, author: `${packageJson.author.name} <${packageJson.author.email}>`, homepage: packageJson.homepage, - license: 'Copyright (c) 2023 WüSpace e. V.' + license: 'MIT. Copyright (c) 2023 WüSpace e. V.' }; // https://vitejs.dev/config/ export default defineConfig({ build: { lib: { - entry: resolve(__dirname, 'src/lib/index.ts'), + entry: [ + resolve(__dirname, 'src/lib/index.ts'), + resolve(__dirname, 'src/lib/mod-application.ts'), + resolve(__dirname, 'src/lib/mod-auth.ts'), + resolve(__dirname, 'src/lib/mod-nats.ts'), + resolve(__dirname, 'src/lib/mod-user-data.ts'), + resolve(__dirname, 'src/lib/mod-utils.ts'), + resolve(__dirname, 'src/lib/mod-widget.ts') + ], name: 'Telestion', - fileName: 'telestion' + fileName: (format, entryName) => + `${entryName}.${format === 'cjs' ? 'cjs' : 'js'}` }, sourcemap: true, rollupOptions: { @@ -36,6 +45,11 @@ export default defineConfig({ } } }, + resolve: { + alias: { + '@wuespace/telestion': resolve(__dirname, 'src/lib') + } + }, plugins: [react(), banner(transformBanner(bannerText))], test: { environment: 'happy-dom'