diff --git a/apps/app-e2e/eslint.config.mjs b/apps/app-e2e/eslint.config.mjs index f3ddd1d7..b48dda2e 100644 --- a/apps/app-e2e/eslint.config.mjs +++ b/apps/app-e2e/eslint.config.mjs @@ -1,11 +1,13 @@ -import path from 'node:path'; +import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import js from '@eslint/js'; + import { FlatCompat } from '@eslint/eslintrc'; +import js from '@eslint/js'; + import baseConfig from '../../eslint.config.mjs'; const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +const __dirname = dirname(__filename); const compat = new FlatCompat({ baseDirectory: __dirname, recommendedConfig: js.configs.recommended, diff --git a/apps/app/src/app/layout/main/main.layout.ts b/apps/app/src/app/layout/main/main.layout.ts index 1fe85eca..43d9b903 100644 --- a/apps/app/src/app/layout/main/main.layout.ts +++ b/apps/app/src/app/layout/main/main.layout.ts @@ -1,4 +1,5 @@ import { NgTemplateOutlet } from '@angular/common'; +import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit, inject, signal } from '@angular/core'; import { Router, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router'; import { SwUpdate } from '@angular/service-worker'; @@ -55,8 +56,10 @@ export default class MainLayout implements OnInit { this.getPings.set(data.data.getPings); } }, - error: (error) => { - this.getPings.set(error.message); + error: (error: unknown) => { + const typedError = error as HttpErrorResponse; + + console.error(typedError.message); }, }); } @@ -78,31 +81,25 @@ export default class MainLayout implements OnInit { if (this.swUpdate.isEnabled) { this.swUpdate.versionUpdates.subscribe({ next: (version) => { - console.log({ version }); - switch (version.type) { case 'VERSION_DETECTED': - alert('New version detected'); + console.log('New version detected. Downloading...'); break; case 'VERSION_READY': - if (confirm('New version of the app is ready. Do you want to reload?')) { + if (confirm('New version of the app is ready. Do you want to install it?')) { + alert('Installing new version...'); + this.swUpdate.activateUpdate().then(() => { - if (confirm('New version installed. Do you want to reload?')) { - location.reload(); - } + location.reload(); }); } break; case 'VERSION_INSTALLATION_FAILED': - alert('Failed to install new version'); + console.error('Failed to install new version.'); break; } }, }); - - // const haveUpdates = await this.swUpdate.checkForUpdate(); - - // console.log({ haveUpdates }); } } } diff --git a/apps/app/src/app/page/example/section/spacing/spacing.page.ts b/apps/app/src/app/page/example/section/spacing/spacing.page.ts index 5cd52e2d..99e7f674 100644 --- a/apps/app/src/app/page/example/section/spacing/spacing.page.ts +++ b/apps/app/src/app/page/example/section/spacing/spacing.page.ts @@ -1,4 +1,3 @@ -import { NgFor } from '@angular/common'; import { Component } from '@angular/core'; import ExampleMenuComponent from '../../component/menu/example-menu.component'; @@ -7,7 +6,7 @@ import ExampleMenuComponent from '../../component/menu/example-menu.component'; standalone: true, templateUrl: './spacing.page.html', styleUrl: './spacing.page.scss', - imports: [ExampleMenuComponent, NgFor], + imports: [ExampleMenuComponent], }) export class SpacingPage { spaces = ['none', 'xs', 'sm', 'md', 'lg', 'xl', 'xxl', 'xxxl']; diff --git a/apps/app/src/app/service/indexed-db/indexed-db.service.ts b/apps/app/src/app/service/indexed-db/indexed-db.service.ts index 0d66f2df..d9dcf848 100644 --- a/apps/app/src/app/service/indexed-db/indexed-db.service.ts +++ b/apps/app/src/app/service/indexed-db/indexed-db.service.ts @@ -1,112 +1,65 @@ import { Injectable } from '@angular/core'; +import { DBSchema, IDBPDatabase, openDB } from 'idb'; import { LocalStorageKey } from './definition/indexed-db-key.enum'; +interface KeyValueStoreSchema extends DBSchema { + KeyValueStore: { + key: LocalStorageKey; + value: unknown; + }; +} + @Injectable({ providedIn: 'root', }) export class IndexedDBService { - private dbName = 'PlaySetOnline'; - private storeName = 'KeyValueStore'; - private dbVersion = 1; - private dbPromise: Promise; + private readonly dbName = 'PlaySetOnline'; + private readonly storeName = 'KeyValueStore'; + private readonly dbVersion = 1; + private readonly dbPromise: Promise>; constructor() { this.dbPromise = this.initDB(); } - async setItem(key: LocalStorageKey, data: T): Promise { + async setItem(key: LocalStorageKey, value: T): Promise { const db = await this.dbPromise; - return new Promise((resolve, reject) => { - const transaction = db.transaction([this.storeName], 'readwrite'); - const store = transaction.objectStore(this.storeName); - const request = store.put({ key, value: data }); - - request.onsuccess = () => { - resolve(); - }; - - request.onerror = (event) => { - reject((event.target as IDBRequest).error); - }; - }); + await db.put(this.storeName, { key, value }); } async getItem(key: LocalStorageKey): Promise { const db = await this.dbPromise; - return new Promise((resolve, reject) => { - const transaction = db.transaction([this.storeName], 'readonly'); - const store = transaction.objectStore(this.storeName); - const request = store.get(key); + const item = await db.get(this.storeName, key); - request.onsuccess = (event) => { - const result = (event.target as IDBRequest).result; - resolve(result ? (result.value as T) : undefined); - }; + const typedItem = item as { value: T } | undefined; - request.onerror = (event) => { - reject((event.target as IDBRequest).error); - }; - }); + return typedItem?.value; } async deleteItem(key: LocalStorageKey): Promise { const db = await this.dbPromise; - return new Promise((resolve, reject) => { - const transaction = db.transaction([this.storeName], 'readwrite'); - const store = transaction.objectStore(this.storeName); - const request = store.delete(key); - - request.onsuccess = () => { - resolve(); - }; - - request.onerror = (event) => { - reject((event.target as IDBRequest).error); - }; - }); + await db.delete(this.storeName, key); } async clearStore(): Promise { const db = await this.dbPromise; - return new Promise((resolve, reject) => { - const transaction = db.transaction([this.storeName], 'readwrite'); - const store = transaction.objectStore(this.storeName); - const request = store.clear(); - - request.onsuccess = () => { - resolve(); - }; - - request.onerror = (event) => { - reject((event.target as IDBRequest).error); - }; - }); + await db.clear(this.storeName); } - private initDB(): Promise { - return new Promise((resolve, reject) => { - const request = indexedDB.open(this.dbName, this.dbVersion); + private initDB(): Promise> { + const storeName = this.storeName; - request.onupgradeneeded = (event) => { - const db = (event.target as IDBOpenDBRequest).result; - if (!db.objectStoreNames.contains(this.storeName)) { - db.createObjectStore(this.storeName, { keyPath: 'key' }); + return openDB(this.dbName, this.dbVersion, { + upgrade(db) { + if (!db.objectStoreNames.contains(storeName)) { + db.createObjectStore(storeName, { keyPath: 'key' }); } - }; - - request.onsuccess = (event) => { - const db = (event.target as IDBOpenDBRequest).result; - resolve(db); - }; - - request.onerror = (event) => { - reject((event.target as IDBOpenDBRequest).error); - }; + }, }); } } diff --git a/cspell.json b/cspell.json index 8563f4ce..0e4c643d 100644 --- a/cspell.json +++ b/cspell.json @@ -7,6 +7,7 @@ "codegen", "commitlint", "devkit", + "IDBP", "mikro", "nestjs", "ngneat", diff --git a/docker-compose.yml b/docker-compose.yml index 78520a6f..af85ad68 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,6 @@ services: MIKRO_ORM_CLI_TS_CONFIG_PATH: apps/api/tsconfig.app.json MIKRO_ORM_CLI_ALWAYS_ALLOW_TS: 1 MIKRO_ORM_CLI_USE_TS_NODE: 1 - NODE_TLS_REJECT_UNAUTHORIZED: 0 PATH: $PATH:/usr/src/app/node_modules/.bin TZ: UTC depends_on: diff --git a/eslint.config.mjs b/eslint.config.mjs index a9bf6f62..e4271b15 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,3 +1,6 @@ +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + import nx from '@nx/eslint-plugin'; import tsParser from '@typescript-eslint/parser'; import eslintPluginImport from 'eslint-plugin-import'; @@ -6,6 +9,11 @@ import rxjs from 'eslint-plugin-rxjs-updated'; import unusedImports from 'eslint-plugin-unused-imports'; import globals from 'globals'; +import eslintErrorsToWarnings from './tools/helpers/eslint-errors-to-warnings.mjs'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + export default [ ...nx.configs['flat/base'], ...nx.configs['flat/typescript'], @@ -14,12 +22,10 @@ export default [ plugins: { prettier, '@nx': nx, - rxjs: rxjs, + rxjs, import: eslintPluginImport, 'unused-imports': unusedImports, }, - }, - { ignores: ['**/dist', 'node_modules', 'libs/api-definitions/src/lib/apollo/operations.ts'], }, { @@ -73,6 +79,9 @@ export default [ parser: tsParser, ecmaVersion: 2023, sourceType: 'module', + parserOptions: { + project: join(__dirname, './tsconfig.base.json'), + }, }, settings: { 'import/ignore': ['node_modules'], @@ -84,15 +93,12 @@ export default [ }, }, rules: { - // ...Object.fromEntries( - // Object.entries(sonarjs.configs.recommended.rules).map(([ruleName, ruleValue]) => { - // return [`${ruleName}`, ruleValue.replace('error', 'warn')]; - // }), - // ), + // ...eslintErrorsToWarnings(sonarjs.configs.recommended.rules), // 'sonarjs/todo-tag': 'off', // 'sonarjs/fixme-tag': 'off', // 'sonarjs/unused-import': 'off', // 'sonarjs/pseudo-random': 'warn', + ...eslintErrorsToWarnings(rxjs.configs.recommended.rules), 'unused-imports/no-unused-imports': 'warn', 'no-unused-private-class-members': 'warn', '@typescript-eslint/no-unused-vars': [ diff --git a/libs/api-sdk/eslint.config.mjs b/libs/api-sdk/eslint.config.mjs index dc003160..b85363ad 100644 --- a/libs/api-sdk/eslint.config.mjs +++ b/libs/api-sdk/eslint.config.mjs @@ -1,12 +1,6 @@ import parser from 'jsonc-eslint-parser'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import js from '@eslint/js'; -import { FlatCompat } from '@eslint/eslintrc'; -import baseConfig from '../../eslint.config.mjs'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +import baseConfig from '../../eslint.config.mjs'; export default [ ...baseConfig, diff --git a/package-lock.json b/package-lock.json index c9d14da4..0380a44e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@playsetonline/source", - "version": "1.0.1", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@playsetonline/source", - "version": "1.0.1", + "version": "1.1.0", "license": "MIT", "dependencies": { "@angular/animations": "18.2.12", @@ -48,6 +48,7 @@ "cookie-parser": "1.4.7", "graphql": "16.9.0", "graphql-subscriptions": "3.0.0", + "idb": "^8.0.0", "mikro-orm": "6.4.0", "ms": "2.1.3", "node-cache": "5.1.2", @@ -23681,6 +23682,12 @@ "postcss": "^8.1.0" } }, + "node_modules/idb": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.0.tgz", + "integrity": "sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==", + "license": "ISC" + }, "node_modules/identity-obj-proxy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", diff --git a/package.json b/package.json index e5ffd5e8..991bd9d8 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "cookie-parser": "1.4.7", "graphql": "16.9.0", "graphql-subscriptions": "3.0.0", + "idb": "^8.0.0", "mikro-orm": "6.4.0", "ms": "2.1.3", "node-cache": "5.1.2", diff --git a/tools/helpers/eslint-errors-to-warnings.mjs b/tools/helpers/eslint-errors-to-warnings.mjs new file mode 100644 index 00000000..fa39c050 --- /dev/null +++ b/tools/helpers/eslint-errors-to-warnings.mjs @@ -0,0 +1,12 @@ +export default function eslintErrorsToWarnings(rules) { + return Object.fromEntries( + Object.entries(rules).map(([ruleName, ruleValue]) => { + ruleValue = + typeof ruleValue === 'string' + ? ruleValue?.replace('error', 'warn') + : ruleValue[0]?.replace('error', 'warn'); + + return [ruleName, ruleValue]; + }), + ); +} diff --git a/tools/helpers/patch-nx-source-map-paths.js b/tools/helpers/patch-nx-source-map-paths.js index ba7c5de7..aa5eea35 100644 --- a/tools/helpers/patch-nx-source-map-paths.js +++ b/tools/helpers/patch-nx-source-map-paths.js @@ -1,16 +1,16 @@ -const path = require('path'); +import { relative } from 'node:path'; /* * Temporary workaround for debugging Node applications being built with webpack and Nx. * See: https://github.com/nrwl/nx/issues/14708#issuecomment-1457996600 */ module.exports = function patchNxSourceMapPaths(config) { - config.output.devtoolModuleFilenameTemplate = function (info) { - const rel = path.relative(process.cwd(), info.absoluteResourcePath); - return `webpack:///./${rel}`; - }; + config.output.devtoolModuleFilenameTemplate = function (info) { + const rel = relative(process.cwd(), info.absoluteResourcePath); + return `webpack:///./${rel}`; + }; - config.devtool = 'source-map'; + config.devtool = 'source-map'; - return config; + return config; };