From 7789e0adb9aefdea0cc723e6e472564d2487252a Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Fri, 25 Oct 2024 03:01:36 +0000 Subject: [PATCH 01/11] add events module + client + dev center - use socket.io admin ui for dev center - use socket.io with events gateway to send and receive events - listen to events on client side to test client connection Currently, this is only a test, send pings to all clients to see that they receive the message. --- client/package.json | 1 + client/proxy.conf.json | 7 + client/src/app/app.component.ts | 32 +++- client/src/app/services/socket.service.ts | 31 ++++ pnpm-lock.yaml | 206 ++++++++++++++++------ server/login-app/swagger-tabs.js | 56 ++++-- server/package.json | 4 + server/socket-io.js | 7 + server/src/app.controller.ts | 9 +- server/src/app.module.ts | 8 +- server/src/custom-socket-io.adapter.ts | 28 +++ server/src/events/events.gateway.spec.ts | 19 ++ server/src/events/events.gateway.ts | 24 +++ server/src/events/events.module.ts | 9 + server/src/main.ts | 8 + 15 files changed, 371 insertions(+), 78 deletions(-) create mode 100644 client/src/app/services/socket.service.ts create mode 100644 server/socket-io.js create mode 100644 server/src/custom-socket-io.adapter.ts create mode 100644 server/src/events/events.gateway.spec.ts create mode 100644 server/src/events/events.gateway.ts create mode 100644 server/src/events/events.module.ts diff --git a/client/package.json b/client/package.json index 0c0f047..50f31a6 100644 --- a/client/package.json +++ b/client/package.json @@ -24,6 +24,7 @@ "beercss": "^3.7.10", "material-dynamic-colors": "^1.1.2", "rxjs": "~7.8.0", + "socket.io-client": "^4.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" }, diff --git a/client/proxy.conf.json b/client/proxy.conf.json index ebb5810..36829f6 100644 --- a/client/proxy.conf.json +++ b/client/proxy.conf.json @@ -10,5 +10,12 @@ "changeOrigin": true, "secure": false, "logLevel": "debug" + }, + "/socket.io": { + "target": "http://localhost:10102/", + "ws": true, + "changeOrigin": true, + "secure": false, + "logLevel": "debug" } } \ No newline at end of file diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 14ff2e7..41d6446 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -1,8 +1,9 @@ -import { combineLatest } from 'rxjs'; +import { combineLatest, Subscription } from 'rxjs'; import { NgFor, NgIf } from '@angular/common'; -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { RouterLink, RouterOutlet } from '@angular/router'; +import { SocketService } from './services/socket.service'; import { AppService } from './app.service'; @Component({ @@ -12,12 +13,33 @@ import { AppService } from './app.service'; templateUrl: './app.component.html', styleUrl: './app.component.scss' }) -export class AppComponent implements OnInit { +export class AppComponent implements OnInit, OnDestroy { loggedInUser: any; + private messageSubscription: Subscription; + messages: string[] = []; + newMessage: string = ''; + constructor( - private appService: AppService - ) {} + private appService: AppService, + private socketService: SocketService + ) { + this.messageSubscription = this.socketService + .on('ping') + .subscribe((data) => { + // this.messages.push(data.text); + console.log('Received ping message:', data); + }); + } + + sendMessage() { + this.socketService.emit('message', { text: this.newMessage }); + this.newMessage = ''; + } + + ngOnDestroy() { + this.messageSubscription.unsubscribe(); + } ngOnInit(): void { const loggedInUserObs = this diff --git a/client/src/app/services/socket.service.ts b/client/src/app/services/socket.service.ts new file mode 100644 index 0000000..266b23d --- /dev/null +++ b/client/src/app/services/socket.service.ts @@ -0,0 +1,31 @@ +import { Observable } from 'rxjs'; +import { io, Socket } from 'socket.io-client'; +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class SocketService { + private socket: Socket; + + constructor() { + this.socket = io(window.location.origin); + } + + emit(event: string, data: any) { + this.socket.emit(event, data); + } + + on(event: string): Observable { + return new Observable((observer) => { + this.socket.on(event, (data) => { + observer.next(data); + }); + + // Handle cleanup + return () => { + this.socket.off(event); + }; + }); + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 713f7bc..5a3acd6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,6 +177,9 @@ importers: rxjs: specifier: ~7.8.0 version: 7.8.1 + socket.io-client: + specifier: ^4.8.0 + version: 4.8.0 tslib: specifier: ^2.3.0 version: 2.7.0 @@ -237,7 +240,7 @@ importers: version: 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': specifier: ^10.0.0 - version: 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + version: 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/devtools-integration': specifier: ^0.1.6 version: 0.1.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(encoding@0.1.13) @@ -250,6 +253,9 @@ importers: '@nestjs/platform-express': specifier: ^10.0.0 version: 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4) + '@nestjs/platform-socket.io': + specifier: ^10.4.6 + version: 10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.6)(rxjs@7.8.1) '@nestjs/schedule': specifier: ^4.1.1 version: 4.1.1(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4) @@ -268,12 +274,18 @@ importers: '@nestjs/typeorm': specifier: ^10.0.2 version: 10.0.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.13.0)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))) + '@nestjs/websockets': + specifier: ^10.4.6 + version: 10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/platform-socket.io@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@octokit/auth-app': specifier: ^7.1.1 version: 7.1.1 '@octokit/core': specifier: ^5.2.0 version: 5.2.0 + '@socket.io/admin-ui': + specifier: ^0.5.1 + version: 0.5.1(socket.io@4.8.0) axios: specifier: ^1.7.7 version: 1.7.7 @@ -315,7 +327,7 @@ importers: version: 1.9.7(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(winston@3.15.0) nestjs-asyncapi: specifier: ^1.3.0 - version: 1.3.0(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/swagger@7.4.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2))(@types/babel__core@7.20.5)(@types/node@20.16.11)(encoding@0.1.13) + version: 1.3.0(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/swagger@7.4.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2))(@nestjs/websockets@10.4.6)(@types/babel__core@7.20.5)(@types/node@20.16.11)(encoding@0.1.13) passport: specifier: ^0.7.0 version: 0.7.0 @@ -346,6 +358,9 @@ importers: smee-client: specifier: ^2.0.3 version: 2.0.3 + socket.io: + specifier: ^4.8.0 + version: 4.8.0 typeorm: specifier: ^0.3.20 version: 0.3.20(pg@8.13.0)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3)) @@ -477,6 +492,12 @@ importers: specifier: ^5.6.2 version: 5.6.3 + simple-client: + dependencies: + socket.io-client: + specifier: ^4.8.0 + version: 4.8.0 + packages: '@ampproject/remapping@2.3.0': @@ -2137,6 +2158,13 @@ packages: '@nestjs/common': ^10.0.0 '@nestjs/core': ^10.0.0 + '@nestjs/platform-socket.io@10.4.6': + resolution: {integrity: sha512-lGv99O7C00wtnGq9M0mcwrOpH2qmuqAXQyvo/d/I7rmaf3OO1Sg8qWDLAnPKHdaumwOL2mnET3kvCJ06MaL6WA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/websockets': ^10.0.0 + rxjs: ^7.1.0 + '@nestjs/schedule@4.1.1': resolution: {integrity: sha512-VxAnCiU4HP0wWw8IdWAVfsGC/FGjyToNjjUtXDEQL6oj+w/N5QDd2VT9k6d7Jbr8PlZuBZNdWtDKSkH5bZ+RXQ==} peerDependencies: @@ -2258,6 +2286,18 @@ packages: rxjs: ^7.2.0 typeorm: ^0.3.0 + '@nestjs/websockets@10.4.6': + resolution: {integrity: sha512-53YqDQylPAOudNFiiBvrN8QrRl/sZ9oEjKbD3wBVgrFREbaiuTySoyyy6HwVs60HW29uQwck+Bp7qkKGjhtQKg==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + '@nestjs/platform-socket.io': ^10.0.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/platform-socket.io': + optional: true + '@ngtools/webpack@17.3.10': resolution: {integrity: sha512-yPKmdbTJzxROAl2NS8P8eHB2mU0BqV2I0ZiKmX6oTetY2Ea4i2WzlTK39pPpG7atmdF2NPWYLXdJWAup+JxSyw==} engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -2624,6 +2664,11 @@ packages: '@smoya/multi-parser@4.1.0': resolution: {integrity: sha512-0q4805I7ZdkKNEbNrbxmBNAdYEAH9aBYCuXiIXCbu8WC0sdRqLWmTsvg/DaNO8ZnsrGhVzy5VITf+8CKlVnGoQ==} + '@socket.io/admin-ui@0.5.1': + resolution: {integrity: sha512-1dlGL2FGm6T+uL1e6iDvbo2eCINwvW7iVbjIblwh5kPPRM1SP8lmZrbFZf4QNJ/cqQ+JLcx49eXGM9WAB4TK7w==} + peerDependencies: + socket.io: '>=3.1.0' + '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -2758,6 +2803,9 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/bcryptjs@2.4.6': + resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} + '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -3510,6 +3558,9 @@ packages: bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + bcryptjs@2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + beercss@3.7.10: resolution: {integrity: sha512-h2tU2eXnh4WUUJPXk971+MS8ja571P/dxrg+7JOuc98ijb1kEKTQvHQxLBmvHee2cKzj0/DppYZphH/PnWBOXA==} @@ -4367,6 +4418,9 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + engine.io-client@6.6.2: + resolution: {integrity: sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw==} + engine.io-parser@5.2.3: resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} engines: {node: '>=10.0.0'} @@ -6627,6 +6681,10 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + object-inspect@1.13.2: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} @@ -7648,6 +7706,10 @@ packages: socket.io-adapter@2.5.5: resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + socket.io-client@4.8.0: + resolution: {integrity: sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw==} + engines: {node: '>=10.0.0'} + socket.io-parser@4.2.4: resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} engines: {node: '>=10.0.0'} @@ -8775,6 +8837,10 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} + engines: {node: '>=0.4.0'} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -11673,7 +11739,7 @@ snapshots: tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.1.0 typescript: 5.3.3 - webpack: 5.94.0 + webpack: 5.94.0(esbuild@0.20.1) webpack-node-externals: 3.0.0 transitivePeerDependencies: - esbuild @@ -11691,7 +11757,7 @@ snapshots: class-transformer: 0.5.1 class-validator: 0.14.1 - '@nestjs/core@10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + '@nestjs/core@10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2(encoding@0.1.13) @@ -11704,13 +11770,14 @@ snapshots: uid: 2.0.2 optionalDependencies: '@nestjs/platform-express': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4) + '@nestjs/websockets': 10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/platform-socket.io@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) transitivePeerDependencies: - encoding '@nestjs/devtools-integration@0.1.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(encoding@0.1.13)': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) chalk: 4.1.2 node-fetch: 2.7.0(encoding@0.1.13) transitivePeerDependencies: @@ -11738,7 +11805,7 @@ snapshots: '@nestjs/platform-express@10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) body-parser: 1.20.3 cors: 2.8.5 express: 4.21.0 @@ -11747,10 +11814,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@nestjs/platform-socket.io@10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.6)(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/websockets': 10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/platform-socket.io@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) + rxjs: 7.8.1 + socket.io: 4.8.0 + tslib: 2.7.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@nestjs/schedule@4.1.1(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) cron: 3.1.7 uuid: 10.0.0 @@ -11779,7 +11858,7 @@ snapshots: '@nestjs/serve-static@4.0.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(express@4.21.1)': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) path-to-regexp: 0.2.5 optionalDependencies: express: 4.21.1 @@ -11788,7 +11867,7 @@ snapshots: dependencies: '@microsoft/tsdoc': 0.15.0 '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) js-yaml: 4.1.0 lodash: 4.17.21 @@ -11802,7 +11881,7 @@ snapshots: '@nestjs/terminus@10.2.3(@nestjs/axios@3.0.3(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(axios@1.7.7)(rxjs@7.8.1))(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/typeorm@10.0.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.13.0)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3))))(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.13.0)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3)))': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) boxen: 5.1.2 check-disk-space: 3.4.0 reflect-metadata: 0.2.2 @@ -11815,7 +11894,7 @@ snapshots: '@nestjs/testing@10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/platform-express@10.4.4)': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) tslib: 2.7.0 optionalDependencies: '@nestjs/platform-express': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4) @@ -11823,18 +11902,30 @@ snapshots: '@nestjs/throttler@6.2.1(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(reflect-metadata@0.2.2)': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) reflect-metadata: 0.2.2 '@nestjs/typeorm@10.0.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(pg@8.13.0)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3)))': dependencies: '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) reflect-metadata: 0.2.2 rxjs: 7.8.1 typeorm: 0.3.20(pg@8.13.0)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.3)) uuid: 9.0.1 + '@nestjs/websockets@10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/platform-socket.io@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + iterare: 1.2.1 + object-hash: 3.0.0 + reflect-metadata: 0.2.2 + rxjs: 7.8.1 + tslib: 2.7.0 + optionalDependencies: + '@nestjs/platform-socket.io': 10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.6)(rxjs@7.8.1) + '@ngtools/webpack@17.3.10(@angular/compiler-cli@17.3.12(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5))(typescript@5.4.5)(webpack@5.94.0(esbuild@0.20.1))': dependencies: '@angular/compiler-cli': 17.3.12(@angular/compiler@17.3.12(@angular/core@17.3.12(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.4.5) @@ -12299,6 +12390,15 @@ snapshots: transitivePeerDependencies: - encoding + '@socket.io/admin-ui@0.5.1(socket.io@4.8.0)': + dependencies: + '@types/bcryptjs': 2.4.6 + bcryptjs: 2.4.3 + debug: 4.3.7 + socket.io: 4.8.0 + transitivePeerDependencies: + - supports-color + '@socket.io/component-emitter@3.1.2': {} '@sqltools/formatter@1.2.5': {} @@ -12520,6 +12620,8 @@ snapshots: dependencies: '@babel/types': 7.25.8 + '@types/bcryptjs@2.4.6': {} + '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 @@ -13529,6 +13631,8 @@ snapshots: dependencies: tweetnacl: 0.14.5 + bcryptjs@2.4.3: {} + beercss@3.7.10: dependencies: material-dynamic-colors: 1.1.2 @@ -14446,6 +14550,18 @@ snapshots: dependencies: once: 1.4.0 + engine.io-client@6.6.2: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + engine.io-parser: 5.2.3 + ws: 8.17.1 + xmlhttprequest-ssl: 2.1.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + engine.io-parser@5.2.3: {} engine.io@6.6.2: @@ -15203,7 +15319,7 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.3.3 - webpack: 5.94.0 + webpack: 5.94.0(esbuild@0.20.1) form-data@2.3.3: dependencies: @@ -17082,15 +17198,17 @@ snapshots: fast-safe-stringify: 2.1.1 winston: 3.15.0 - nestjs-asyncapi@1.3.0(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/swagger@7.4.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2))(@types/babel__core@7.20.5)(@types/node@20.16.11)(encoding@0.1.13): + nestjs-asyncapi@1.3.0(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/swagger@7.4.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2))(@nestjs/websockets@10.4.6)(@types/babel__core@7.20.5)(@types/node@20.16.11)(encoding@0.1.13): dependencies: '@asyncapi/generator': 1.13.1(@types/babel__core@7.20.5)(@types/node@20.16.11)(encoding@0.1.13) '@asyncapi/html-template': 0.28.4(encoding@0.1.13) '@nestjs/common': 10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.4(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.4)(@nestjs/websockets@10.4.6)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/swagger': 7.4.2(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) js-yaml: 4.1.0 reflect-metadata: 0.2.1 + optionalDependencies: + '@nestjs/websockets': 10.4.6(@nestjs/common@10.4.4(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.4)(@nestjs/platform-socket.io@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -17315,6 +17433,8 @@ snapshots: object-assign@4.1.1: {} + object-hash@3.0.0: {} + object-inspect@1.13.2: {} object-keys@1.1.1: {} @@ -18426,6 +18546,17 @@ snapshots: - supports-color - utf-8-validate + socket.io-client@4.8.0: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + engine.io-client: 6.6.2 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + socket.io-parser@4.2.4: dependencies: '@socket.io/component-emitter': 3.1.2 @@ -18756,15 +18887,6 @@ snapshots: optionalDependencies: esbuild: 0.20.1 - terser-webpack-plugin@5.3.10(webpack@5.94.0): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 3.3.0 - serialize-javascript: 6.0.2 - terser: 5.29.1 - webpack: 5.94.0 - terser@5.29.1: dependencies: '@jridgewell/source-map': 0.3.6 @@ -18892,7 +19014,7 @@ snapshots: semver: 7.6.3 source-map: 0.7.4 typescript: 5.6.3 - webpack: 5.94.0 + webpack: 5.94.0(esbuild@0.20.1) ts-node@10.9.2(@types/node@20.16.11)(typescript@4.9.5): dependencies: @@ -19427,36 +19549,6 @@ snapshots: typed-assert: 1.0.9 webpack: 5.94.0(esbuild@0.20.1) - webpack@5.94.0: - dependencies: - '@types/estree': 1.0.6 - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/wasm-edit': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.12.1 - acorn-import-attributes: 1.9.5(acorn@8.12.1) - browserslist: 4.24.0 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.5.4 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.94.0) - watchpack: 2.4.2 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - webpack@5.94.0(esbuild@0.20.1): dependencies: '@types/estree': 1.0.6 @@ -19631,6 +19723,8 @@ snapshots: xmlchars@2.2.0: {} + xmlhttprequest-ssl@2.1.2: {} + xtend@4.0.2: {} y18n@5.0.8: {} diff --git a/server/login-app/swagger-tabs.js b/server/login-app/swagger-tabs.js index a66d0a6..592951b 100644 --- a/server/login-app/swagger-tabs.js +++ b/server/login-app/swagger-tabs.js @@ -1,6 +1,11 @@ -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener('DOMContentLoaded', function() { setTimeout(async () => { - console.log('====== test?'); + localStorage.setItem('dark_theme', 'true'); + localStorage.setItem('namespace', '/admin'); + localStorage.setItem('parser', 'default'); + localStorage.setItem('path', '/socket.io'); + localStorage.setItem('server_url', window.location.origin); + localStorage.setItem('ws_only', 'false'); const swaggerTopbar = document.querySelector('.topbar'); const swaggerUi = document.querySelector('div.swagger-ui'); @@ -65,6 +70,18 @@ document.addEventListener('DOMContentLoaded', function () { swaggerContainer.appendChild(nestjsDevToolsIframe); } + const socketIoAdminIframe = document.createElement('iframe'); + socketIoAdminIframe.src = '/api/socket-io'; + socketIoAdminIframe.style.display = 'none'; + socketIoAdminIframe.style.width = '100%'; + socketIoAdminIframe.style.height = '100%'; + socketIoAdminIframe.style.border = 'none'; + socketIoAdminIframe.style.flexGrow = '1'; + + if (true) { + swaggerContainer.appendChild(socketIoAdminIframe); + } + // add tabs under the topbar const tabs = document.createElement('div'); // get active tab based on the current url @@ -79,17 +96,20 @@ document.addEventListener('DOMContentLoaded', function () { allTabsHtml.push('Swagger JSON'); } - if (showAsyncDocs) { - allTabsHtml.push('Async Docs'); - } - if (showSmeeClient) { - allTabsHtml.push('Smee webhooks'); + allTabsHtml.push('webhooks proxy'); } if (showNestjsDevTools) { allTabsHtml.push('NestJs DevTools'); + } + if (true) { + allTabsHtml.push('Sockets'); + } + + if (showAsyncDocs) { + allTabsHtml.push('Async Docs'); } tabs.innerHTML = allTabsHtml.join(''); @@ -119,47 +139,59 @@ document.addEventListener('DOMContentLoaded', function () { swaggerJsonIframe.style.display = 'none'; asyncDocsIframe.style.display = 'none'; nestjsDevToolsIframe.style.display = 'none'; + socketIoAdminIframe.style.display = 'none'; } else if (tab === 'json') { swaggerUi.style.display = 'none'; smeeIframe.style.display = 'none'; swaggerJsonIframe.style.display = 'block'; asyncDocsIframe.style.display = 'none'; nestjsDevToolsIframe.style.display = 'none'; + socketIoAdminIframe.style.display = 'none'; } else if (tab === 'async') { swaggerUi.style.display = 'none'; smeeIframe.style.display = 'none'; swaggerJsonIframe.style.display = 'none'; asyncDocsIframe.style.display = 'block'; nestjsDevToolsIframe.style.display = 'none'; + socketIoAdminIframe.style.display = 'none'; } else if (tab === 'smee') { swaggerUi.style.display = 'none'; smeeIframe.style.display = 'block'; swaggerJsonIframe.style.display = 'none'; asyncDocsIframe.style.display = 'none'; nestjsDevToolsIframe.style.display = 'none'; + socketIoAdminIframe.style.display = 'none'; } else if (tab === 'nestjs-devtools') { swaggerUi.style.display = 'none'; smeeIframe.style.display = 'none'; swaggerJsonIframe.style.display = 'none'; asyncDocsIframe.style.display = 'none'; nestjsDevToolsIframe.style.display = 'block'; + socketIoAdminIframe.style.display = 'none'; // open a new tab to nestjs devtools window.open('https://devtools.nestjs.com/', '_blank'); + } else if (tab === 'socket-io-admin') { + swaggerUi.style.display = 'none'; + smeeIframe.style.display = 'none'; + swaggerJsonIframe.style.display = 'none'; + asyncDocsIframe.style.display = 'none'; + nestjsDevToolsIframe.style.display = 'none'; + socketIoAdminIframe.style.display = 'block'; } } function getCurrentActiveTab() { const pathname = window.location.pathname; const hostname = window.location.hostname; - + if (pathname.endsWith('json')) { return { target: tabs.querySelector('#json') }; } - + if (pathname.endsWith('async')) { return { target: tabs.querySelector('#async') }; } - + // check if using smee at smee.kibibit.io if (hostname === 'smee.kibibit.io') { return { target: tabs.querySelector('#smee') }; @@ -168,8 +200,8 @@ document.addEventListener('DOMContentLoaded', function () { if (hostname === 'devtools.nestjs.com') { return { target: tabs.querySelector('#nestjs-devtools') }; } - + return { target: tabs.querySelector('#swagger-ui') }; } }, 750); -}); \ No newline at end of file +}); diff --git a/server/package.json b/server/package.json index 9f05808..3fccd55 100644 --- a/server/package.json +++ b/server/package.json @@ -41,14 +41,17 @@ "@nestjs/jwt": "^10.2.0", "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.4.6", "@nestjs/schedule": "^4.1.1", "@nestjs/serve-static": "^4.0.2", "@nestjs/swagger": "^7.4.2", "@nestjs/terminus": "^10.2.3", "@nestjs/throttler": "^6.2.1", "@nestjs/typeorm": "^10.0.2", + "@nestjs/websockets": "^10.4.6", "@octokit/auth-app": "^7.1.1", "@octokit/core": "^5.2.0", + "@socket.io/admin-ui": "^0.5.1", "axios": "^1.7.7", "badge-maker": "^4.0.0", "bitbucket": "^2.12.0", @@ -73,6 +76,7 @@ "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "smee-client": "^2.0.3", + "socket.io": "^4.8.0", "typeorm": "^0.3.20", "winston": "^3.14.2" }, diff --git a/server/socket-io.js b/server/socket-io.js new file mode 100644 index 0000000..1530a8a --- /dev/null +++ b/server/socket-io.js @@ -0,0 +1,7 @@ +/*! + * Socket.IO v4.3.2 + * (c) 2014-2021 Guillermo Rauch + * Released under the MIT License. + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).io=e()}(this,(function(){"use strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,s=!0,a=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return s=t.done,t},e:function(t){a=!0,i=t},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw i}}}}var d=/^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,y=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],v=function(t){var e=t,n=t.indexOf("["),r=t.indexOf("]");-1!=n&&-1!=r&&(t=t.substring(0,n)+t.substring(n,r).replace(/:/g,";")+t.substring(r,t.length));for(var o,i,s=d.exec(t||""),a={},c=14;c--;)a[y[c]]=s[c]||"";return-1!=n&&-1!=r&&(a.source=e,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a.pathNames=function(t,e){var n=/\/{2,9}/g,r=e.replace(n,"/").split("/");"/"!=e.substr(0,1)&&0!==e.length||r.splice(0,1);"/"==e.substr(e.length-1,1)&&r.splice(r.length-1,1);return r}(0,a.path),a.queryKey=(o=a.query,i={},o.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(t,e,n){e&&(i[e]=n)})),i),a};var m={exports:{}};try{m.exports="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(t){m.exports=!1}var g=m.exports,k="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")();function b(t){var e=t.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!e||g))return new XMLHttpRequest}catch(t){}if(!e)try{return new(k[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(t){}}function w(t){for(var e=arguments.length,n=new Array(e>1?e-1:0),r=1;r1?{type:C[n],data:t.substring(1)}:{type:C[n]}:S},M=function(t,e){if(I){var n=function(t){var e,n,r,o,i,s=.75*t.length,a=t.length,c=0;"="===t[t.length-1]&&(s--,"="===t[t.length-2]&&s--);var u=new ArrayBuffer(s),h=new Uint8Array(u);for(e=0;e>4,h[c++]=(15&r)<<4|o>>2,h[c++]=(3&o)<<6|63&i;return u}(t);return U(n,e)}return{base64:!0,data:t}},U=function(t,e){return"blob"===e&&t instanceof ArrayBuffer?new Blob([t]):t},V=String.fromCharCode(30),H=function(t){i(o,t);var n=h(o);function o(t){var r;return e(this,o),(r=n.call(this)).writable=!1,A(c(r),t),r.opts=t,r.query=t.query,r.readyState="",r.socket=t.socket,r}return r(o,[{key:"onError",value:function(t,e){var n=new Error(t);return n.type="TransportError",n.description=e,f(s(o.prototype),"emit",this).call(this,"error",n),this}},{key:"open",value:function(){return"closed"!==this.readyState&&""!==this.readyState||(this.readyState="opening",this.doOpen()),this}},{key:"close",value:function(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this}},{key:"send",value:function(t){"open"===this.readyState&&this.write(t)}},{key:"onOpen",value:function(){this.readyState="open",this.writable=!0,f(s(o.prototype),"emit",this).call(this,"open")}},{key:"onData",value:function(t){var e=F(t,this.socket.binaryType);this.onPacket(e)}},{key:"onPacket",value:function(t){f(s(o.prototype),"emit",this).call(this,"packet",t)}},{key:"onClose",value:function(){this.readyState="closed",f(s(o.prototype),"emit",this).call(this,"close")}}]),o}(R),K="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),Y={},z=0,$=0;function W(t){var e="";do{e=K[t%64]+e,t=Math.floor(t/64)}while(t>0);return e}function J(){var t=W(+new Date);return t!==D?(z=0,D=t):t+"."+W(z++)}for(;$<64;$++)Y[K[$]]=$;J.encode=W,J.decode=function(t){var e=0;for($=0;$0&&void 0!==arguments[0]?arguments[0]:{};return o(t,{xd:this.xd,xs:this.xs},this.opts),new nt(this.uri(),t)}},{key:"doWrite",value:function(t,e){var n=this,r=this.request({method:"POST",data:t});r.on("success",e),r.on("error",(function(t){n.onError("xhr post error",t)}))}},{key:"doPoll",value:function(){var t=this,e=this.request();e.on("data",this.onData.bind(this)),e.on("error",(function(e){t.onError("xhr poll error",e)})),this.pollXhr=e}}]),s}(Q),nt=function(t){i(o,t);var n=h(o);function o(t,r){var i;return e(this,o),A(c(i=n.call(this)),r),i.opts=r,i.method=r.method||"GET",i.uri=t,i.async=!1!==r.async,i.data=void 0!==r.data?r.data:null,i.create(),i}return r(o,[{key:"create",value:function(){var t=this,e=w(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");e.xdomain=!!this.opts.xd,e.xscheme=!!this.opts.xs;var n=this.xhr=new b(e);try{n.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders)for(var r in n.setDisableHeaderCheck&&n.setDisableHeaderCheck(!0),this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(r)&&n.setRequestHeader(r,this.opts.extraHeaders[r])}catch(t){}if("POST"===this.method)try{n.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(t){}try{n.setRequestHeader("Accept","*/*")}catch(t){}"withCredentials"in n&&(n.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(n.timeout=this.opts.requestTimeout),n.onreadystatechange=function(){4===n.readyState&&(200===n.status||1223===n.status?t.onLoad():t.setTimeoutFn((function(){t.onError("number"==typeof n.status?n.status:0)}),0))},n.send(this.data)}catch(e){return void this.setTimeoutFn((function(){t.onError(e)}),0)}"undefined"!=typeof document&&(this.index=o.requestsCount++,o.requests[this.index]=this)}},{key:"onSuccess",value:function(){this.emit("success"),this.cleanup()}},{key:"onData",value:function(t){this.emit("data",t),this.onSuccess()}},{key:"onError",value:function(t){this.emit("error",t),this.cleanup(!0)}},{key:"cleanup",value:function(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=Z,t)try{this.xhr.abort()}catch(t){}"undefined"!=typeof document&&delete o.requests[this.index],this.xhr=null}}},{key:"onLoad",value:function(){var t=this.xhr.responseText;null!==t&&this.onData(t)}},{key:"abort",value:function(){this.cleanup()}}]),o}(R);if(nt.requestsCount=0,nt.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",rt);else if("function"==typeof addEventListener){addEventListener("onpagehide"in k?"pagehide":"unload",rt,!1)}function rt(){for(var t in nt.requests)nt.requests.hasOwnProperty(t)&&nt.requests[t].abort()}var ot="function"==typeof Promise&&"function"==typeof Promise.resolve?function(t){return Promise.resolve().then(t)}:function(t,e){return e(t,0)},it=k.WebSocket||k.MozWebSocket,st="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase(),at=function(t){i(o,t);var n=h(o);function o(t){var r;return e(this,o),(r=n.call(this,t)).supportsBinary=!t.forceBase64,r}return r(o,[{key:"name",get:function(){return"websocket"}},{key:"doOpen",value:function(){if(this.check()){var t=this.uri(),e=this.opts.protocols,n=st?{}:w(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(n.headers=this.opts.extraHeaders);try{this.ws=st?new it(t,e,n):e?new it(t,e):new it(t)}catch(t){return this.emit("error",t)}this.ws.binaryType=this.socket.binaryType||"arraybuffer",this.addEventListeners()}}},{key:"addEventListeners",value:function(){var t=this;this.ws.onopen=function(){t.opts.autoUnref&&t.ws._socket.unref(),t.onOpen()},this.ws.onclose=this.onClose.bind(this),this.ws.onmessage=function(e){return t.onData(e.data)},this.ws.onerror=function(e){return t.onError("websocket error",e)}}},{key:"write",value:function(t){var e=this;this.writable=!1;for(var n=function(n){var r=t[n],o=n===t.length-1;x(r,e.supportsBinary,(function(t){try{e.ws.send(t)}catch(t){}o&&ot((function(){e.writable=!0,e.emit("drain")}),e.setTimeoutFn)}))},r=0;r1&&void 0!==arguments[1]?arguments[1]:{};return e(this,a),r=s.call(this),n&&"object"===t(n)&&(i=n,n=null),n?(n=v(n),i.hostname=n.host,i.secure="https"===n.protocol||"wss"===n.protocol,i.port=n.port,n.query&&(i.query=n.query)):i.host&&(i.hostname=v(i.host).host),A(c(r),i),r.secure=null!=i.secure?i.secure:"undefined"!=typeof location&&"https:"===location.protocol,i.hostname&&!i.port&&(i.port=r.secure?"443":"80"),r.hostname=i.hostname||("undefined"!=typeof location?location.hostname:"localhost"),r.port=i.port||("undefined"!=typeof location&&location.port?location.port:r.secure?"443":"80"),r.transports=i.transports||["polling","websocket"],r.readyState="",r.writeBuffer=[],r.prevBufferLen=0,r.opts=o({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},i),r.opts.path=r.opts.path.replace(/\/$/,"")+"/","string"==typeof r.opts.query&&(r.opts.query=G.decode(r.opts.query)),r.id=null,r.upgrades=null,r.pingInterval=null,r.pingTimeout=null,r.pingTimeoutTimer=null,"function"==typeof addEventListener&&(r.opts.closeOnBeforeunload&&addEventListener("beforeunload",(function(){r.transport&&(r.transport.removeAllListeners(),r.transport.close())}),!1),"localhost"!==r.hostname&&(r.offlineEventListener=function(){r.onClose("transport close")},addEventListener("offline",r.offlineEventListener,!1))),r.open(),r}return r(a,[{key:"createTransport",value:function(t){var e=function(t){var e={};for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}(this.opts.query);e.EIO=4,e.transport=t,this.id&&(e.sid=this.id);var n=o({},this.opts.transportOptions[t],this.opts,{query:e,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return new ct[t](n)}},{key:"open",value:function(){var t,e=this;if(this.opts.rememberUpgrade&&a.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))t="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((function(){e.emitReserved("error","No transports available")}),0);t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(t){return this.transports.shift(),void this.open()}t.open(),this.setTransport(t)}},{key:"setTransport",value:function(t){var e=this;this.transport&&this.transport.removeAllListeners(),this.transport=t,t.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(function(){e.onClose("transport close")}))}},{key:"probe",value:function(t){var e=this,n=this.createTransport(t),r=!1;a.priorWebsocketSuccess=!1;var o=function(){r||(n.send([{type:"ping",data:"probe"}]),n.once("packet",(function(t){if(!r)if("pong"===t.type&&"probe"===t.data){if(e.upgrading=!0,e.emitReserved("upgrading",n),!n)return;a.priorWebsocketSuccess="websocket"===n.name,e.transport.pause((function(){r||"closed"!==e.readyState&&(f(),e.setTransport(n),n.send([{type:"upgrade"}]),e.emitReserved("upgrade",n),n=null,e.upgrading=!1,e.flush())}))}else{var o=new Error("probe error");o.transport=n.name,e.emitReserved("upgradeError",o)}})))};function i(){r||(r=!0,f(),n.close(),n=null)}var s=function(t){var r=new Error("probe error: "+t);r.transport=n.name,i(),e.emitReserved("upgradeError",r)};function c(){s("transport closed")}function u(){s("socket closed")}function h(t){n&&t.name!==n.name&&i()}var f=function(){n.removeListener("open",o),n.removeListener("error",s),n.removeListener("close",c),e.off("close",u),e.off("upgrading",h)};n.once("open",o),n.once("error",s),n.once("close",c),this.once("close",u),this.once("upgrading",h),n.open()}},{key:"onOpen",value:function(){if(this.readyState="open",a.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade&&this.transport.pause)for(var t=0,e=this.upgrades.length;t0;case bt.ACK:case bt.BINARY_ACK:return Array.isArray(n)}}}]),a}(R);var Et=function(){function t(n){e(this,t),this.packet=n,this.buffers=[],this.reconPack=n}return r(t,[{key:"takeBinaryData",value:function(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){var e=gt(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}},{key:"finishedReconstruction",value:function(){this.reconPack=null,this.buffers=[]}}]),t}(),At=Object.freeze({__proto__:null,protocol:5,get PacketType(){return bt},Encoder:wt,Decoder:_t});function Rt(t,e,n){return t.on(e,n),function(){t.off(e,n)}}var Tt=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1}),Ot=function(t){i(o,t);var n=h(o);function o(t,r,i){var s;return e(this,o),(s=n.call(this)).connected=!1,s.disconnected=!0,s.receiveBuffer=[],s.sendBuffer=[],s.ids=0,s.acks={},s.flags={},s.io=t,s.nsp=r,i&&i.auth&&(s.auth=i.auth),s.io._autoConnect&&s.open(),s}return r(o,[{key:"subEvents",value:function(){if(!this.subs){var t=this.io;this.subs=[Rt(t,"open",this.onopen.bind(this)),Rt(t,"packet",this.onpacket.bind(this)),Rt(t,"error",this.onerror.bind(this)),Rt(t,"close",this.onclose.bind(this))]}}},{key:"active",get:function(){return!!this.subs}},{key:"connect",value:function(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}},{key:"open",value:function(){return this.connect()}},{key:"send",value:function(){for(var t=arguments.length,e=new Array(t),n=0;n1?e-1:0),r=1;r0&&t.jitter<=1?t.jitter:0,this.attempts=0}St.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},St.prototype.reset=function(){this.attempts=0},St.prototype.setMin=function(t){this.ms=t},St.prototype.setMax=function(t){this.max=t},St.prototype.setJitter=function(t){this.jitter=t};var Nt=function(n){i(s,n);var o=h(s);function s(n,r){var i,a;e(this,s),(i=o.call(this)).nsps={},i.subs=[],n&&"object"===t(n)&&(r=n,n=void 0),(r=r||{}).path=r.path||"/socket.io",i.opts=r,A(c(i),r),i.reconnection(!1!==r.reconnection),i.reconnectionAttempts(r.reconnectionAttempts||1/0),i.reconnectionDelay(r.reconnectionDelay||1e3),i.reconnectionDelayMax(r.reconnectionDelayMax||5e3),i.randomizationFactor(null!==(a=r.randomizationFactor)&&void 0!==a?a:.5),i.backoff=new Ct({min:i.reconnectionDelay(),max:i.reconnectionDelayMax(),jitter:i.randomizationFactor()}),i.timeout(null==r.timeout?2e4:r.timeout),i._readyState="closed",i.uri=n;var u=r.parser||At;return i.encoder=new u.Encoder,i.decoder=new u.Decoder,i._autoConnect=!1!==r.autoConnect,i._autoConnect&&i.open(),i}return r(s,[{key:"reconnection",value:function(t){return arguments.length?(this._reconnection=!!t,this):this._reconnection}},{key:"reconnectionAttempts",value:function(t){return void 0===t?this._reconnectionAttempts:(this._reconnectionAttempts=t,this)}},{key:"reconnectionDelay",value:function(t){var e;return void 0===t?this._reconnectionDelay:(this._reconnectionDelay=t,null===(e=this.backoff)||void 0===e||e.setMin(t),this)}},{key:"randomizationFactor",value:function(t){var e;return void 0===t?this._randomizationFactor:(this._randomizationFactor=t,null===(e=this.backoff)||void 0===e||e.setJitter(t),this)}},{key:"reconnectionDelayMax",value:function(t){var e;return void 0===t?this._reconnectionDelayMax:(this._reconnectionDelayMax=t,null===(e=this.backoff)||void 0===e||e.setMax(t),this)}},{key:"timeout",value:function(t){return arguments.length?(this._timeout=t,this):this._timeout}},{key:"maybeReconnectOnOpen",value:function(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}},{key:"open",value:function(t){var e=this;if(~this._readyState.indexOf("open"))return this;this.engine=new ut(this.uri,this.opts);var n=this.engine,r=this;this._readyState="opening",this.skipReconnect=!1;var o=Rt(n,"open",(function(){r.onopen(),t&&t()})),i=Rt(n,"error",(function(n){r.cleanup(),r._readyState="closed",e.emitReserved("error",n),t?t(n):r.maybeReconnectOnOpen()}));if(!1!==this._timeout){var s=this._timeout;0===s&&o();var a=this.setTimeoutFn((function(){o(),n.close(),n.emit("error",new Error("timeout"))}),s);this.opts.autoUnref&&a.unref(),this.subs.push((function(){clearTimeout(a)}))}return this.subs.push(o),this.subs.push(i),this}},{key:"connect",value:function(t){return this.open(t)}},{key:"onopen",value:function(){this.cleanup(),this._readyState="open",this.emitReserved("open");var t=this.engine;this.subs.push(Rt(t,"ping",this.onping.bind(this)),Rt(t,"data",this.ondata.bind(this)),Rt(t,"error",this.onerror.bind(this)),Rt(t,"close",this.onclose.bind(this)),Rt(this.decoder,"decoded",this.ondecoded.bind(this)))}},{key:"onping",value:function(){this.emitReserved("ping")}},{key:"ondata",value:function(t){this.decoder.add(t)}},{key:"ondecoded",value:function(t){this.emitReserved("packet",t)}},{key:"onerror",value:function(t){this.emitReserved("error",t)}},{key:"socket",value:function(t,e){var n=this.nsps[t];return n||(n=new Ot(this,t,e),this.nsps[t]=n),n}},{key:"_destroy",value:function(t){for(var e=0,n=Object.keys(this.nsps);e=this._reconnectionAttempts)this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{var n=this.backoff.duration();this._reconnecting=!0;var r=this.setTimeoutFn((function(){e.skipReconnect||(t.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((function(n){n?(e._reconnecting=!1,e.reconnect(),t.emitReserved("reconnect_error",n)):e.onreconnect()})))}),n);this.opts.autoUnref&&r.unref(),this.subs.push((function(){clearTimeout(r)}))}}},{key:"onreconnect",value:function(){var t=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",t)}}]),s}(R),Bt={};function xt(e,n){"object"===t(e)&&(n=e,e=void 0);var r,o=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2?arguments[2]:void 0,r=t;n=n||"undefined"!=typeof location&&location,null==t&&(t=n.protocol+"//"+n.host),"string"==typeof t&&("/"===t.charAt(0)&&(t="/"===t.charAt(1)?n.protocol+t:n.host+t),/^(https?|wss?):\/\//.test(t)||(t=void 0!==n?n.protocol+"//"+t:"https://"+t),r=v(t)),r.port||(/^(http|ws)$/.test(r.protocol)?r.port="80":/^(http|ws)s$/.test(r.protocol)&&(r.port="443")),r.path=r.path||"/";var o=-1!==r.host.indexOf(":")?"["+r.host+"]":r.host;return r.id=r.protocol+"://"+o+":"+r.port+e,r.href=r.protocol+"://"+o+(n&&n.port===r.port?"":":"+r.port),r}(e,(n=n||{}).path||"/socket.io"),i=o.source,s=o.id,a=o.path,c=Bt[s]&&a in Bt[s].nsps;return n.forceNew||n["force new connection"]||!1===n.multiplex||c?r=new Nt(i,n):(Bt[s]||(Bt[s]=new Nt(i,n)),r=Bt[s]),o.query&&!n.query&&(n.query=o.queryKey),r.socket(o.path,n)}return o(xt,{Manager:Nt,Socket:Ot,io:xt,connect:xt}),xt})); +//# sourceMappingURL=socket.io.min.js.map \ No newline at end of file diff --git a/server/src/app.controller.ts b/server/src/app.controller.ts index abf7491..89d4c1a 100644 --- a/server/src/app.controller.ts +++ b/server/src/app.controller.ts @@ -1,6 +1,6 @@ import { join } from 'path'; -import { readJSON } from 'fs-extra'; +import { readFileSync, readJSON } from 'fs-extra'; import { chain } from 'lodash'; import { Controller, Get } from '@nestjs/common'; @@ -53,9 +53,14 @@ export class AppController { smeeUrl: this.appService.smeeUrl, showSwaggerUi: true, showSwaggerJson: false, - showAsyncDocs: true, + showAsyncDocs: false, showSmeeClient: this.appService.smeeUrl ? true : false, showNestjsDevTools: true }; } + + @Get('/socket.io') + getSocketIo() { + return readFileSync(join(configService.appRoot, './socket-io.js'), 'utf8'); + } } diff --git a/server/src/app.module.ts b/server/src/app.module.ts index c742006..4db2cd0 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -20,11 +20,12 @@ import { ShieldsModule } from '@kb-shields'; import { UsersModule } from '@kb-users'; import { WebhooksModule } from '@kb-webhooks'; +import { EventsGateway } from './events/events.gateway'; import { HealthModule } from './health/health.module'; import { SystemsModule } from './systems/systems.module'; +import { TasksModule } from './tasks/tasks.module'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { TasksModule } from './tasks/tasks.module'; @Module({ imports: [ @@ -35,7 +36,7 @@ import { TasksModule } from './tasks/tasks.module'; // Adjust the path to your client build directory rootPath: join(configService.appRoot, 'client'), // Exclude API routes - exclude: [ '/api*', '/login*' ] + exclude: [ '/api*', '/login*', '/socket.io*' ] }), ThrottlerModule.forRoot([ { ttl: 60000, @@ -69,7 +70,8 @@ import { TasksModule } from './tasks/tasks.module'; useClass: DbExceptionFilter }, AppService, - SmeeService + SmeeService, + EventsGateway ] }) export class AppModule { diff --git a/server/src/custom-socket-io.adapter.ts b/server/src/custom-socket-io.adapter.ts new file mode 100644 index 0000000..9c3057a --- /dev/null +++ b/server/src/custom-socket-io.adapter.ts @@ -0,0 +1,28 @@ +import { Server, ServerOptions } from 'socket.io'; +import { instrument } from '@socket.io/admin-ui'; + +import { IoAdapter } from '@nestjs/platform-socket.io'; + +export class CustomSocketIoAdapter extends IoAdapter { + createIOServer(port: number, options?: ServerOptions): Server { + options = { + ...options, + path: '/socket.io', // Use default path or adjust as needed + cors: { + origin: '*', // Adjust for your security requirements + methods: [ 'GET', 'POST' ] + } + }; + + const server = super.createIOServer(port, options); + + instrument(server, { + auth: false, // Adjust authentication as needed + mode: 'development' + // Specify the namespace if needed + // namespaceName: '/admin', + }); + + return server; + } +} diff --git a/server/src/events/events.gateway.spec.ts b/server/src/events/events.gateway.spec.ts new file mode 100644 index 0000000..cf620cf --- /dev/null +++ b/server/src/events/events.gateway.spec.ts @@ -0,0 +1,19 @@ +import { Test, TestingModule } from '@nestjs/testing'; + +import { EventsGateway } from './events.gateway'; + +describe('EventsGateway', () => { + let gateway: EventsGateway; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ EventsGateway ] + }).compile(); + + gateway = module.get(EventsGateway); + }); + + it('should be defined', () => { + expect(gateway).toBeDefined(); + }); +}); diff --git a/server/src/events/events.gateway.ts b/server/src/events/events.gateway.ts new file mode 100644 index 0000000..7876f37 --- /dev/null +++ b/server/src/events/events.gateway.ts @@ -0,0 +1,24 @@ +import { Server } from 'socket.io'; + +import { SubscribeMessage, WebSocketGateway, WebSocketServer } from '@nestjs/websockets'; + +@WebSocketGateway() +export class EventsGateway { + @WebSocketServer() + server: Server; + + constructor() { + setInterval(() => { + this.sendPingMessage(); + }, 30000); + } + @SubscribeMessage('message') + handleMessage(client: any, payload: any): string { + return 'Hello world!'; + } + + async sendPingMessage() { + console.log('Sending ping message to all clients...'); + this.server.emit('ping', 'dev check'); + } +} diff --git a/server/src/events/events.module.ts b/server/src/events/events.module.ts new file mode 100644 index 0000000..28c45a4 --- /dev/null +++ b/server/src/events/events.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { EventsGateway } from './events.gateway'; + +@Module({ + providers: [ + EventsGateway + ], +}) +export class EventsModule {} diff --git a/server/src/main.ts b/server/src/main.ts index 229acc8..7b57010 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -12,6 +12,7 @@ import { NestExpressApplication } from '@nestjs/platform-express'; import { configService, loggerInstance } from '@kb-config'; import { AppModule } from './app.module'; +import { CustomSocketIoAdapter } from './custom-socket-io.adapter'; import { Documentation } from './documentation'; import { logo } from './logo'; @@ -64,6 +65,13 @@ async function bootstrap() { prefix: '/login' }); + app.useStaticAssets(join(__dirname, '..', 'node_modules', '@socket.io', 'admin-ui', 'ui', 'dist'), { + prefix: '/api/socket-io' + }); + + // Use your custom Socket.IO adapter (see next step) + app.useWebSocketAdapter(new CustomSocketIoAdapter(app)); + await Documentation.addDocumentation(app); await app.listen(configService.config.PORT); From ae4ead66513470a24c376d4963e0c181b39d6504 Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Fri, 25 Oct 2024 03:01:52 +0000 Subject: [PATCH 02/11] lint ignore socket-io.js file --- server/.eslintignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/.eslintignore b/server/.eslintignore index 819568d..9d3c0e4 100644 --- a/server/.eslintignore +++ b/server/.eslintignore @@ -1,4 +1,5 @@ .storybook/**/* tester-app/**/* dist/**/* -.eslintrc.js \ No newline at end of file +.eslintrc.js +socket-io.js \ No newline at end of file From ded974d2bdbcbf1c3b5f0639fa3489ccfca8df3b Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Fri, 25 Oct 2024 03:02:24 +0000 Subject: [PATCH 03/11] lint fix all server files --- server/src/app.module.ts | 7 +++-- server/src/app.service.ts | 3 +- server/src/auth/auth.module.ts | 2 +- server/src/config/config.service.ts | 2 +- server/src/config/smee/smee.service.ts | 2 +- server/src/systems/github/github.service.ts | 10 +++---- server/src/tasks/tasks.module.ts | 6 ++-- server/src/tasks/tasks.service.spec.ts | 3 +- server/src/tasks/tasks.service.ts | 33 +++++++++++---------- server/src/webhooks/engines/github.event.ts | 2 +- server/src/webhooks/webhooks.controller.ts | 2 +- server/src/webhooks/webhooks.service.ts | 1 + 12 files changed, 40 insertions(+), 33 deletions(-) diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 4db2cd0..8e552c2 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -26,6 +26,7 @@ import { SystemsModule } from './systems/systems.module'; import { TasksModule } from './tasks/tasks.module'; import { AppController } from './app.controller'; import { AppService } from './app.service'; +import { EventsModule } from './events/events.module'; @Module({ imports: [ @@ -53,7 +54,8 @@ import { AppService } from './app.service'; ShieldsModule, HealthModule, SystemsModule, - TasksModule + TasksModule, + EventsModule ], controllers: [ AppController ], providers: [ @@ -70,8 +72,7 @@ import { AppService } from './app.service'; useClass: DbExceptionFilter }, AppService, - SmeeService, - EventsGateway + SmeeService ] }) export class AppModule { diff --git a/server/src/app.service.ts b/server/src/app.service.ts index 96f914f..e570db4 100644 --- a/server/src/app.service.ts +++ b/server/src/app.service.ts @@ -1,6 +1,7 @@ -import { configService, Logger, SmeeService } from '@kb-config'; import { Injectable } from '@nestjs/common'; +import { configService, Logger, SmeeService } from '@kb-config'; + @Injectable() export class AppService { diff --git a/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts index 1d6bb20..43b9f40 100644 --- a/server/src/auth/auth.module.ts +++ b/server/src/auth/auth.module.ts @@ -1,12 +1,12 @@ import { Module } from '@nestjs/common'; +import { configService, Logger } from '@kb-config'; import { UsersModule } from '@kb-users'; import { BitbucketModule } from './bitbucket/bitbucket.module'; import { GithubModule } from './github/github.module'; import { GitlabModule } from './gitlab/gitlab.module'; import { AuthController } from './auth.controller'; -import { configService, Logger } from '@kb-config'; const logger = new Logger('AuthModule'); diff --git a/server/src/config/config.service.ts b/server/src/config/config.service.ts index 570bb69..ef28f61 100644 --- a/server/src/config/config.service.ts +++ b/server/src/config/config.service.ts @@ -5,8 +5,8 @@ import { TypeOrmModuleOptions } from '@nestjs/typeorm'; import { ConfigService, IConfigServiceOptions } from '@kibibit/configit'; -import { AchievibitConfig } from './achievibit.config'; import { Logger } from './logger/logger'; +import { AchievibitConfig } from './achievibit.config'; const ENV_DEFAULT = 'development'; diff --git a/server/src/config/smee/smee.service.ts b/server/src/config/smee/smee.service.ts index ff84a83..2b30ccd 100644 --- a/server/src/config/smee/smee.service.ts +++ b/server/src/config/smee/smee.service.ts @@ -1,9 +1,9 @@ +import { noop } from 'lodash'; import SmeeClient from 'smee-client'; import { BeforeApplicationShutdown, Injectable } from '@nestjs/common'; import { configService, Logger } from '@kb-config'; -import { noop } from 'lodash'; @Injectable() export class SmeeService implements BeforeApplicationShutdown { diff --git a/server/src/systems/github/github.service.ts b/server/src/systems/github/github.service.ts index f37f760..747177b 100644 --- a/server/src/systems/github/github.service.ts +++ b/server/src/systems/github/github.service.ts @@ -53,7 +53,7 @@ export class GithubService { auth: token }); - const { data } = await installationOctokit.request(`GET /installation/repositories`, { + const { data } = await installationOctokit.request('GET /installation/repositories', { headers: { 'X-GitHub-Api-Version': '2022-11-28', accept: 'application/vnd.github+json', @@ -70,17 +70,17 @@ export class GithubService { authStrategy: createAppAuth, auth: { appId: configService.config.GITHUB_APP_ID, - privateKey: this.privateKey, - }, + privateKey: this.privateKey + } }); - + return await octokit.request('GET /app/installations', { headers: { 'X-GitHub-Api-Version': '2022-11-28', accept: 'application/vnd.github+json', per_page: 100 } - }) + }); } private generateGithubAppJwt(): string { diff --git a/server/src/tasks/tasks.module.ts b/server/src/tasks/tasks.module.ts index c3d72ac..edae2f8 100644 --- a/server/src/tasks/tasks.module.ts +++ b/server/src/tasks/tasks.module.ts @@ -1,13 +1,15 @@ import { Module } from '@nestjs/common'; import { ScheduleModule } from '@nestjs/schedule'; -import { TasksService } from './tasks.service'; + import { SystemsModule } from '@kb-systems'; +import { TasksService } from './tasks.service'; + @Module({ imports: [ ScheduleModule.forRoot(), SystemsModule ], - providers: [TasksService] + providers: [ TasksService ] }) export class TasksModule {} diff --git a/server/src/tasks/tasks.service.spec.ts b/server/src/tasks/tasks.service.spec.ts index cb48230..c557a9c 100644 --- a/server/src/tasks/tasks.service.spec.ts +++ b/server/src/tasks/tasks.service.spec.ts @@ -1,4 +1,5 @@ import { Test, TestingModule } from '@nestjs/testing'; + import { TasksService } from './tasks.service'; describe('TasksService', () => { @@ -6,7 +7,7 @@ describe('TasksService', () => { beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [TasksService], + providers: [ TasksService ] }).compile(); service = module.get(TasksService); diff --git a/server/src/tasks/tasks.service.ts b/server/src/tasks/tasks.service.ts index 2530227..afa4e72 100644 --- a/server/src/tasks/tasks.service.ts +++ b/server/src/tasks/tasks.service.ts @@ -1,9 +1,10 @@ +import { bgBlue, bgYellow } from 'colors'; +import { pad } from 'lodash'; + +import { Injectable } from '@nestjs/common'; + import { Logger } from '@kb-config'; import { GithubService } from '@kb-systems'; -import { Injectable } from '@nestjs/common'; -import { Cron, CronExpression, Interval, Timeout } from '@nestjs/schedule'; -import { bgBlue, bgCyan, rainbow, bgYellow } from 'colors'; -import { pad } from 'lodash'; @Injectable() export class TasksService { @@ -29,21 +30,21 @@ export class TasksService { logger: Logger = this.logger ) { try { - const installations = await this.githubService.getAppInstallations(); + const installations = await this.githubService.getAppInstallations(); - if (installations?.data?.length === 0) { - logger.verbose('No installations found'); - return; - } + if (installations?.data?.length === 0) { + logger.verbose('No installations found'); + return; + } - for (const installation of installations.data) { - const installationReposLean = await this.syncGithubAppInstallation( - installation, - logger - ); - } + for (const installation of installations.data) { + const installationReposLean = await this.syncGithubAppInstallation( + installation, + logger + ); + } - return installations; + return installations; } catch (error) { this.logger.error(error); } diff --git a/server/src/webhooks/engines/github.event.ts b/server/src/webhooks/engines/github.event.ts index bae7ab5..e5901e6 100644 --- a/server/src/webhooks/engines/github.event.ts +++ b/server/src/webhooks/engines/github.event.ts @@ -35,4 +35,4 @@ export class GitHubEvent { get isPullRequestReviewComment() { return this.eventType === 'pull_request_review_comment'; } -} \ No newline at end of file +} diff --git a/server/src/webhooks/webhooks.controller.ts b/server/src/webhooks/webhooks.controller.ts index 08b4e9a..7619c01 100644 --- a/server/src/webhooks/webhooks.controller.ts +++ b/server/src/webhooks/webhooks.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Post, UseGuards, Headers } from '@nestjs/common'; +import { Body, Controller, Headers, Post, UseGuards } from '@nestjs/common'; import { ApiBody, ApiExcludeEndpoint, ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger'; import { configService, Logger } from '@kb-config'; diff --git a/server/src/webhooks/webhooks.service.ts b/server/src/webhooks/webhooks.service.ts index d9cae14..fa2d811 100644 --- a/server/src/webhooks/webhooks.service.ts +++ b/server/src/webhooks/webhooks.service.ts @@ -3,6 +3,7 @@ import * as crypto from 'crypto'; import { Injectable } from '@nestjs/common'; import { configService, Logger } from '@kb-config'; + import { GitHubEvent } from './engines/github.event'; @Injectable() From dc4940330b5cd26ed31d6d89737770b6cdea3ffe Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Wed, 30 Oct 2024 22:09:55 +0000 Subject: [PATCH 04/11] change location of nestjs devtools tab --- server/login-app/swagger-tabs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/login-app/swagger-tabs.js b/server/login-app/swagger-tabs.js index 592951b..00f7d67 100644 --- a/server/login-app/swagger-tabs.js +++ b/server/login-app/swagger-tabs.js @@ -100,10 +100,6 @@ document.addEventListener('DOMContentLoaded', function() { allTabsHtml.push('webhooks proxy'); } - if (showNestjsDevTools) { - allTabsHtml.push('NestJs DevTools'); - } - if (true) { allTabsHtml.push('Sockets'); } @@ -112,6 +108,10 @@ document.addEventListener('DOMContentLoaded', function() { allTabsHtml.push('Async Docs'); } + if (showNestjsDevTools) { + allTabsHtml.push('NestJs DevTools'); + } + tabs.innerHTML = allTabsHtml.join(''); tabs.classList.add('kb-tabs'); From 835c7172e6e8e5eb261613241a0527a7d4573b78 Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Wed, 30 Oct 2024 22:10:10 +0000 Subject: [PATCH 05/11] update pnpm lock --- pnpm-lock.yaml | 51 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a3acd6..2a366de 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -492,12 +492,6 @@ importers: specifier: ^5.6.2 version: 5.6.3 - simple-client: - dependencies: - socket.io-client: - specifier: ^4.8.0 - version: 4.8.0 - packages: '@ampproject/remapping@2.3.0': @@ -11739,7 +11733,7 @@ snapshots: tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.1.0 typescript: 5.3.3 - webpack: 5.94.0(esbuild@0.20.1) + webpack: 5.94.0 webpack-node-externals: 3.0.0 transitivePeerDependencies: - esbuild @@ -15319,7 +15313,7 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.3.3 - webpack: 5.94.0(esbuild@0.20.1) + webpack: 5.94.0 form-data@2.3.3: dependencies: @@ -18887,6 +18881,15 @@ snapshots: optionalDependencies: esbuild: 0.20.1 + terser-webpack-plugin@5.3.10(webpack@5.94.0): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.29.1 + webpack: 5.94.0 + terser@5.29.1: dependencies: '@jridgewell/source-map': 0.3.6 @@ -19014,7 +19017,7 @@ snapshots: semver: 7.6.3 source-map: 0.7.4 typescript: 5.6.3 - webpack: 5.94.0(esbuild@0.20.1) + webpack: 5.94.0 ts-node@10.9.2(@types/node@20.16.11)(typescript@4.9.5): dependencies: @@ -19549,6 +19552,36 @@ snapshots: typed-assert: 1.0.9 webpack: 5.94.0(esbuild@0.20.1) + webpack@5.94.0: + dependencies: + '@types/estree': 1.0.6 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.12.1 + acorn-import-attributes: 1.9.5(acorn@8.12.1) + browserslist: 4.24.0 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.5.4 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(webpack@5.94.0) + watchpack: 2.4.2 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + webpack@5.94.0(esbuild@0.20.1): dependencies: '@types/estree': 1.0.6 From 754da7cf1877002ef92e70ac5cec2040c9f5fbd2 Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Thu, 31 Oct 2024 00:40:15 +0000 Subject: [PATCH 06/11] add postman to extension recommendations --- .devcontainer/devcontainer.json | 3 ++- .vscode/extensions.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d664881..5dec59f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -36,7 +36,8 @@ "github.vscode-github-actions", "formulahendry.auto-rename-tag", "donjayamanne.githistory", - "oderwat.indent-rainbow" + "oderwat.indent-rainbow", + "Postman.postman-for-vscode" ], "settings": { "terminal.integrated.shell.linux": "/bin/zsh" diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 7cdfef2..ba4eeae 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,6 +4,7 @@ "dbaeumer.vscode-eslint", "stylelint.vscode-stylelint", "johnpapa.vscode-peacock", - "streetsidesoftware.code-spell-checker" + "streetsidesoftware.code-spell-checker", + "postman.postman-for-vscode" ] } \ No newline at end of file From c77ab84e3ed4b7dc9fe92bd5ddda105afc7e8246 Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Tue, 5 Nov 2024 22:34:50 +0000 Subject: [PATCH 07/11] run lint on server project --- server/login-app/swagger-tabs.js | 2 +- server/src/app.module.ts | 9 ++++----- server/src/auth/bitbucket/bitbucket.controller.ts | 6 +++--- server/src/auth/github/github.controller.ts | 6 +++--- server/src/auth/gitlab/gitlab.controller.ts | 9 ++++++--- server/src/config/index.ts | 2 ++ server/src/custom-socket-io.adapter.ts | 9 ++++++--- server/src/events/events.module.ts | 3 ++- server/src/events/index.ts | 6 ++++++ server/src/migrations/index.ts | 5 +++++ server/src/models/index.ts | 1 + server/src/systems/github/github.service.ts | 9 ++++++--- server/src/tasks/index.ts | 6 ++++++ server/src/webhooks/index.ts | 1 + server/tsconfig.json | 4 +++- 15 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 server/src/events/index.ts create mode 100644 server/src/migrations/index.ts create mode 100644 server/src/tasks/index.ts diff --git a/server/login-app/swagger-tabs.js b/server/login-app/swagger-tabs.js index 00f7d67..ffe34e5 100644 --- a/server/login-app/swagger-tabs.js +++ b/server/login-app/swagger-tabs.js @@ -1,7 +1,7 @@ document.addEventListener('DOMContentLoaded', function() { setTimeout(async () => { localStorage.setItem('dark_theme', 'true'); - localStorage.setItem('namespace', '/admin'); + localStorage.setItem('namespace', '/admin'); localStorage.setItem('parser', 'default'); localStorage.setItem('path', '/socket.io'); localStorage.setItem('server_url', window.location.origin); diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 8e552c2..295c4cd 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -9,24 +9,23 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { AuthModule } from '@kb-auth'; import { configService, SmeeService } from '@kb-config'; +import { EventsModule } from '@kb-events'; import { DbExceptionFilter } from '@kb-filters'; import { DisableInProductionGuard } from '@kb-guards'; +import { HealthModule } from '@kb-health'; import { LoggerMiddleware } from '@kb-middleware'; import { OrganizationsModule } from '@kb-organizations'; import { PullRequestsModule } from '@kb-pull-requests'; import { RepositoriesModule } from '@kb-repositories'; import { SessionUserModule } from '@kb-session-user'; import { ShieldsModule } from '@kb-shields'; +import { SystemsModule } from '@kb-systems'; +import { TasksModule } from '@kb-tasks'; import { UsersModule } from '@kb-users'; import { WebhooksModule } from '@kb-webhooks'; -import { EventsGateway } from './events/events.gateway'; -import { HealthModule } from './health/health.module'; -import { SystemsModule } from './systems/systems.module'; -import { TasksModule } from './tasks/tasks.module'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { EventsModule } from './events/events.module'; @Module({ imports: [ diff --git a/server/src/auth/bitbucket/bitbucket.controller.ts b/server/src/auth/bitbucket/bitbucket.controller.ts index a285510..a1076b4 100644 --- a/server/src/auth/bitbucket/bitbucket.controller.ts +++ b/server/src/auth/bitbucket/bitbucket.controller.ts @@ -48,9 +48,9 @@ export class BitbucketController { res.cookie('kibibit-jwt', accessToken, { httpOnly: true, - secure: true, // Cookie only sent over HTTPS - sameSite: 'none', // Cookie sent on cross-site requests - maxAge: 3600000 // Cookie expiration time + secure: true, + sameSite: 'none', + maxAge: 3600000 }); // if client is NOT a browser, return the token diff --git a/server/src/auth/github/github.controller.ts b/server/src/auth/github/github.controller.ts index 010dbee..0e86239 100644 --- a/server/src/auth/github/github.controller.ts +++ b/server/src/auth/github/github.controller.ts @@ -47,9 +47,9 @@ export class GithubController { res.cookie('kibibit-jwt', accessToken, { httpOnly: true, - secure: true, // Cookie only sent over HTTPS - sameSite: 'none', // Cookie sent on cross-site requests - maxAge: 3600000 // Cookie expiration time + secure: true, + sameSite: 'none', + maxAge: 3600000 }); // if client is NOT a browser, return the token diff --git a/server/src/auth/gitlab/gitlab.controller.ts b/server/src/auth/gitlab/gitlab.controller.ts index 15eb511..3f6c585 100644 --- a/server/src/auth/gitlab/gitlab.controller.ts +++ b/server/src/auth/gitlab/gitlab.controller.ts @@ -48,9 +48,12 @@ export class GitlabController { res.cookie('kibibit-jwt', accessToken, { httpOnly: true, - secure: true, // Cookie only sent over HTTPS - sameSite: 'none', // Cookie sent on cross-site requests - maxAge: 3600000 // Cookie expiration time + // Cookie only sent over HTTPS + secure: true, + // Cookie sent on cross-site requests + sameSite: 'none', + // Cookie expiration time in ms: 1 hour + maxAge: 3600000 }); // if client is NOT a browser, return the token diff --git a/server/src/config/index.ts b/server/src/config/index.ts index 3a74bc7..047db78 100644 --- a/server/src/config/index.ts +++ b/server/src/config/index.ts @@ -7,3 +7,5 @@ export * from './config.service'; export * from './logger/logger'; export * from './logger/winston.logger'; export * from './smee/smee.service'; +export * from './smee/webhooks-capture/github-webhook-mock.type'; +export * from './smee/webhooks-capture/installation.webhook'; diff --git a/server/src/custom-socket-io.adapter.ts b/server/src/custom-socket-io.adapter.ts index 9c3057a..7d5716a 100644 --- a/server/src/custom-socket-io.adapter.ts +++ b/server/src/custom-socket-io.adapter.ts @@ -7,9 +7,11 @@ export class CustomSocketIoAdapter extends IoAdapter { createIOServer(port: number, options?: ServerOptions): Server { options = { ...options, - path: '/socket.io', // Use default path or adjust as needed + // Use default path or adjust as needed + path: '/socket.io', cors: { - origin: '*', // Adjust for your security requirements + // Adjust for your security requirements + origin: '*', methods: [ 'GET', 'POST' ] } }; @@ -17,7 +19,8 @@ export class CustomSocketIoAdapter extends IoAdapter { const server = super.createIOServer(port, options); instrument(server, { - auth: false, // Adjust authentication as needed + // Adjust authentication as needed + auth: false, mode: 'development' // Specify the namespace if needed // namespaceName: '/admin', diff --git a/server/src/events/events.module.ts b/server/src/events/events.module.ts index 28c45a4..15e20ba 100644 --- a/server/src/events/events.module.ts +++ b/server/src/events/events.module.ts @@ -1,9 +1,10 @@ import { Module } from '@nestjs/common'; + import { EventsGateway } from './events.gateway'; @Module({ providers: [ EventsGateway - ], + ] }) export class EventsModule {} diff --git a/server/src/events/index.ts b/server/src/events/index.ts new file mode 100644 index 0000000..ce65799 --- /dev/null +++ b/server/src/events/index.ts @@ -0,0 +1,6 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './events.gateway'; +export * from './events.module'; diff --git a/server/src/migrations/index.ts b/server/src/migrations/index.ts new file mode 100644 index 0000000..6666b42 --- /dev/null +++ b/server/src/migrations/index.ts @@ -0,0 +1,5 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './1727707536844-initial-table-definitions'; diff --git a/server/src/models/index.ts b/server/src/models/index.ts index 66eb796..b7aa690 100644 --- a/server/src/models/index.ts +++ b/server/src/models/index.ts @@ -3,6 +3,7 @@ */ export * from './Integration.entity'; +export * from './achievement.entity'; export * from './api.model'; export * from './organization.entity'; export * from './pr-status.enum'; diff --git a/server/src/systems/github/github.service.ts b/server/src/systems/github/github.service.ts index 747177b..5577864 100644 --- a/server/src/systems/github/github.service.ts +++ b/server/src/systems/github/github.service.ts @@ -11,7 +11,7 @@ import { SystemEnum, User } from '@kb-models'; import { RepositoriesService } from '@kb-repositories'; import { UsersService } from '@kb-users'; -export interface InstallationAccessTokenResponse { +export interface IInstallationAccessTokenResponse { token: string; expires_at: string; // Add other fields from the response if needed @@ -84,7 +84,8 @@ export class GithubService { } private generateGithubAppJwt(): string { - const now = Math.floor(Date.now() / 1000); // Current time in seconds + // Current time in seconds + const now = Math.floor(Date.now() / 1000); const payload = { // Issued at time @@ -184,7 +185,9 @@ export class GithubService { } const data = await response.json(); - return data; // This includes the 'account' information + + // This includes the 'account' information + return data; } async getInstallationRepositories(installationAccessToken: number, user: User): Promise { diff --git a/server/src/tasks/index.ts b/server/src/tasks/index.ts new file mode 100644 index 0000000..c99c21c --- /dev/null +++ b/server/src/tasks/index.ts @@ -0,0 +1,6 @@ +/** + * @file Automatically generated by barrelsby. + */ + +export * from './tasks.module'; +export * from './tasks.service'; diff --git a/server/src/webhooks/index.ts b/server/src/webhooks/index.ts index dc70e88..5e093e8 100644 --- a/server/src/webhooks/index.ts +++ b/server/src/webhooks/index.ts @@ -5,3 +5,4 @@ export * from './webhooks.controller'; export * from './webhooks.module'; export * from './webhooks.service'; +export * from './engines/github.event'; diff --git a/server/tsconfig.json b/server/tsconfig.json index fb20620..777f070 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -36,7 +36,9 @@ "@kb-users": ["src/users/index"], "@kb-webhooks": ["src/webhooks/index"], "@kb-systems": ["src/systems/index"], - "@kb-tasks": ["src/tasks/index"] + "@kb-tasks": ["src/tasks/index"], + "@kb-events": ["src/events/index"], + "@kb-health": ["src/health/index"] } } } From 42102052a517c3b6a4318ecbd34491d6368b493f Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Tue, 5 Nov 2024 22:35:27 +0000 Subject: [PATCH 08/11] show async docs on dev center --- server/src/app.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/app.controller.ts b/server/src/app.controller.ts index 89d4c1a..e57d4b1 100644 --- a/server/src/app.controller.ts +++ b/server/src/app.controller.ts @@ -53,7 +53,7 @@ export class AppController { smeeUrl: this.appService.smeeUrl, showSwaggerUi: true, showSwaggerJson: false, - showAsyncDocs: false, + showAsyncDocs: true, showSmeeClient: this.appService.smeeUrl ? true : false, showNestjsDevTools: true }; From 91439dddd0a59ecf694f7b563364ca226d233ab8 Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Tue, 5 Nov 2024 22:36:22 +0000 Subject: [PATCH 09/11] add pronunciation of achievibit as an api endpoint --- server/src/app.controller.ts | 20 +++++++++++++++++++- server/src/app.service.ts | 12 +++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/server/src/app.controller.ts b/server/src/app.controller.ts index e57d4b1..34c4f0a 100644 --- a/server/src/app.controller.ts +++ b/server/src/app.controller.ts @@ -3,7 +3,7 @@ import { join } from 'path'; import { readFileSync, readJSON } from 'fs-extra'; import { chain } from 'lodash'; -import { Controller, Get } from '@nestjs/common'; +import { Controller, Get, Header } from '@nestjs/common'; import { ApiOkResponse, ApiOperation } from '@nestjs/swagger'; import { configService, Logger } from '@kb-config'; @@ -63,4 +63,22 @@ export class AppController { getSocketIo() { return readFileSync(join(configService.appRoot, './socket-io.js'), 'utf8'); } + + @Get('api/pronunciation') + @Header('Content-Type', 'audio/mpeg') + @ApiOperation({ summary: 'Get Word Pronunciation for achievibit' }) + @ApiOkResponse({ + description: 'Returns an audio file for the word "achievibit"', + content: { + 'audio/mpeg': { + schema: { + type: 'string', + format: 'binary' + } + } + } + }) + getWordPronunciation() { + return this.appService.getWordPronunciation(); + } } diff --git a/server/src/app.service.ts b/server/src/app.service.ts index e570db4..0ea2bd8 100644 --- a/server/src/app.service.ts +++ b/server/src/app.service.ts @@ -1,4 +1,8 @@ -import { Injectable } from '@nestjs/common'; +import { join } from 'path'; + +import { createReadStream } from 'fs-extra'; + +import { Injectable, StreamableFile } from '@nestjs/common'; import { configService, Logger, SmeeService } from '@kb-config'; @@ -24,4 +28,10 @@ export class AppService { getHello(): string { return 'Hello World!'; } + + getWordPronunciation() { + const file = createReadStream(join(configService.appRoot, 'achieveebeet.mp3')); + + return new StreamableFile(file); + } } From 645803ca33d9686e59c21bef88d0b86dcaacf14b Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Tue, 5 Nov 2024 22:38:04 +0000 Subject: [PATCH 10/11] make example tests better --- e2e/example.spec.ts | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/e2e/example.spec.ts b/e2e/example.spec.ts index 529e40e..6755ae1 100644 --- a/e2e/example.spec.ts +++ b/e2e/example.spec.ts @@ -1,18 +1,43 @@ import { expect, test } from '@playwright/test'; -test('has title', async ({ page }) => { - await page.goto('https://playwright.dev/'); +test('achievibit test', async ({ page }) => { + await page.goto('http://localhost:10101'); // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/Playwright/); + await expect(page).toHaveTitle(/achievibit/); + + await expect(page.getByRole('heading', { name: 'achievibit' })).toBeVisible(); +}); + +test('login with github', async ({ page }) => { + await page.goto('http://localhost:10101'); + + // Click the login with github button. + await page.getByRole('link', { name: 'Login with GitHub' }).click(); + + // expect to be redirected to github login page + await expect(page).toHaveURL(/github/); + await expect(page.getByText('Sign in to GitHub to continue')).toBeVisible(); +}); + +test('login with gitlab', async ({ page }) => { + await page.goto('http://localhost:10101'); + + // Click the login with gitlab button. + await page.getByRole('link', { name: 'Login with GitLab' }).click(); + + // expect to be redirected to gitlab login page + await expect(page).toHaveURL(/gitlab/); + await expect(page.getByRole('heading', { name: 'Verify you are human by' })).toBeVisible(); }); -test('get started link', async ({ page }) => { - await page.goto('https://playwright.dev/'); +test('login with bitbucket', async ({ page }) => { + await page.goto('http://localhost:10101'); - // Click the get started link. - await page.getByRole('link', { name: 'Get started' }).click(); + // Click the login with bitbucket button. + await page.getByRole('link', { name: 'Login with Bitbucket' }).click(); - // Expects page to have a heading with the name of Installation. - await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); + // expect to be redirected to bitbucket login page + await expect(page).toHaveURL(/bitbucket/); + await expect(page.getByTestId('username')).toBeVisible(); }); From 02bf6003be9a4b0b6d1c990f861154ea5a529272 Mon Sep 17 00:00:00 2001 From: Neil Kalman Date: Tue, 5 Nov 2024 22:38:58 +0000 Subject: [PATCH 11/11] disable auto save and make pinned tabs on new row --- .vscode/settings.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0ec3738..fb2bef5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "files.associations": { "*.json": "json" }, + "files.autoSave": "off", "workbench.colorTheme": "Andromeda Bordered", "indentRainbow.indicatorStyle": "light", "indentRainbow.colors": [ @@ -10,6 +11,7 @@ "rgba(255,127,255,0.3)", "rgba(79,236,236,0.3)" ], + "workbench.editor.pinnedTabsOnSeparateRow": true, "indentRainbow.lightIndicatorStyleLineWidth": 2, "gitlens.statusBar.enabled": false, "peacock.showColorInStatusBar": false, @@ -51,6 +53,7 @@ "scss.validate": false, "stylelint.validate": [ "css", "scss" ], "cSpell.words": [ + "achieveebeet", "achievibit", "adpyke", "autoimport", @@ -88,6 +91,7 @@ "ritwickdey", "Smee", "steoates", + "Streamable", "stylelint", "stylelintrc", "thatkookooguy",