From 63446fda8188a59dbe3a056b8c01e97d50aac773 Mon Sep 17 00:00:00 2001 From: addisonbeck Date: Sat, 9 Aug 2025 12:21:31 -0400 Subject: [PATCH] refactor: introduce @bitwarden/platform-utils --- .github/CODEOWNERS | 1 + .../abstractions/platform-utils.service.ts | 58 +------------------ libs/platform-utils/README.md | 5 ++ libs/platform-utils/eslint.config.mjs | 3 + libs/platform-utils/jest.config.js | 10 ++++ libs/platform-utils/package.json | 11 ++++ libs/platform-utils/project.json | 33 +++++++++++ libs/platform-utils/src/index.ts | 58 +++++++++++++++++++ .../src/platform-utils.service.ts | 0 .../platform-utils/src/platform-utils.spec.ts | 8 +++ libs/platform-utils/tsconfig.eslint.json | 6 ++ libs/platform-utils/tsconfig.json | 13 +++++ libs/platform-utils/tsconfig.lib.json | 10 ++++ libs/platform-utils/tsconfig.spec.json | 10 ++++ libs/token-provider/src/device.request.ts | 25 ++++++++ package-lock.json | 9 +++ tsconfig.base.json | 1 + 17 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 libs/platform-utils/README.md create mode 100644 libs/platform-utils/eslint.config.mjs create mode 100644 libs/platform-utils/jest.config.js create mode 100644 libs/platform-utils/package.json create mode 100644 libs/platform-utils/project.json create mode 100644 libs/platform-utils/src/index.ts create mode 100644 libs/platform-utils/src/platform-utils.service.ts create mode 100644 libs/platform-utils/src/platform-utils.spec.ts create mode 100644 libs/platform-utils/tsconfig.eslint.json create mode 100644 libs/platform-utils/tsconfig.json create mode 100644 libs/platform-utils/tsconfig.lib.json create mode 100644 libs/platform-utils/tsconfig.spec.json create mode 100644 libs/token-provider/src/device.request.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e986e0214d1..a1db902bebc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -104,6 +104,7 @@ libs/state @bitwarden/team-platform-dev libs/state-test-utils @bitwarden/team-platform-dev libs/device-type @bitwarden/team-platform-dev libs/encoding @bitwarden/team-platform-dev +libs/platform-utils @bitwarden/team-platform-dev # Web utils used across app and connectors apps/web/src/utils/ @bitwarden/team-platform-dev # Web core and shared files diff --git a/libs/common/src/platform/abstractions/platform-utils.service.ts b/libs/common/src/platform/abstractions/platform-utils.service.ts index 7586da5a564..5a643369bfe 100644 --- a/libs/common/src/platform/abstractions/platform-utils.service.ts +++ b/libs/common/src/platform/abstractions/platform-utils.service.ts @@ -1,57 +1 @@ -import { ClientType, DeviceType } from "../../enums"; - -interface ToastOptions { - timeout?: number; -} - -export type ClipboardOptions = { - allowHistory?: boolean; - clearing?: boolean; - clearMs?: number; - window?: Window; -}; - -export abstract class PlatformUtilsService { - abstract getDevice(): DeviceType; - abstract getDeviceString(): string; - abstract getClientType(): ClientType; - abstract isFirefox(): boolean; - abstract isChrome(): boolean; - abstract isEdge(): boolean; - abstract isOpera(): boolean; - abstract isVivaldi(): boolean; - abstract isSafari(): boolean; - abstract isMacAppStore(): boolean; - abstract isViewOpen(): Promise; - abstract launchUri(uri: string, options?: any): void; - abstract getApplicationVersion(): Promise; - abstract getApplicationVersionNumber(): Promise; - abstract supportsWebAuthn(win: Window): boolean; - abstract supportsDuo(): boolean; - /** - * Returns true if the device supports autofill functionality - */ - abstract supportsAutofill(): boolean; - /** - * Returns true if the device supports native file downloads without - * the need for `target="_blank"` - */ - abstract supportsFileDownloads(): boolean; - /** - * @deprecated use `@bitwarden/components/ToastService.showToast` instead - * - * Jira: [CL-213](https://bitwarden.atlassian.net/browse/CL-213) - */ - abstract showToast( - type: "error" | "success" | "warning" | "info", - title: string, - text: string | string[], - options?: ToastOptions, - ): void; - abstract isDev(): boolean; - abstract isSelfHost(): boolean; - abstract copyToClipboard(text: string, options?: ClipboardOptions): void | boolean; - abstract readFromClipboard(): Promise; - abstract supportsSecureStorage(): boolean; - abstract getAutofillKeyboardShortcut(): Promise; -} +export { ClipboardOptions, PlatformUtilsService } from "@bitwarden/platform-utils"; diff --git a/libs/platform-utils/README.md b/libs/platform-utils/README.md new file mode 100644 index 00000000000..0556f58e8eb --- /dev/null +++ b/libs/platform-utils/README.md @@ -0,0 +1,5 @@ +# platform-utils + +Owned by: platform + +Assorted utils for working with toasts, device type, clipboard, etc. This library needs to be broken up diff --git a/libs/platform-utils/eslint.config.mjs b/libs/platform-utils/eslint.config.mjs new file mode 100644 index 00000000000..9c37d10e3ff --- /dev/null +++ b/libs/platform-utils/eslint.config.mjs @@ -0,0 +1,3 @@ +import baseConfig from "../../eslint.config.mjs"; + +export default [...baseConfig]; diff --git a/libs/platform-utils/jest.config.js b/libs/platform-utils/jest.config.js new file mode 100644 index 00000000000..69cb17a62f5 --- /dev/null +++ b/libs/platform-utils/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + displayName: "platform-utils", + preset: "../../jest.preset.js", + testEnvironment: "node", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/libs/platform-utils", +}; diff --git a/libs/platform-utils/package.json b/libs/platform-utils/package.json new file mode 100644 index 00000000000..e377345f8a1 --- /dev/null +++ b/libs/platform-utils/package.json @@ -0,0 +1,11 @@ +{ + "name": "@bitwarden/platform-utils", + "version": "0.0.1", + "description": "Assorted utils for working with toasts, device type, clipboard, etc. This library needs to be broken up", + "private": true, + "type": "commonjs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "GPL-3.0", + "author": "platform" +} diff --git a/libs/platform-utils/project.json b/libs/platform-utils/project.json new file mode 100644 index 00000000000..9ec7c651ef2 --- /dev/null +++ b/libs/platform-utils/project.json @@ -0,0 +1,33 @@ +{ + "name": "platform-utils", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/platform-utils/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/platform-utils", + "main": "libs/platform-utils/src/index.ts", + "tsConfig": "libs/platform-utils/tsconfig.lib.json", + "assets": ["libs/platform-utils/*.md"] + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/platform-utils/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/platform-utils/jest.config.js" + } + } + } +} diff --git a/libs/platform-utils/src/index.ts b/libs/platform-utils/src/index.ts new file mode 100644 index 00000000000..4aa396edf42 --- /dev/null +++ b/libs/platform-utils/src/index.ts @@ -0,0 +1,58 @@ +import { ClientType } from "@bitwarden/client-type"; +import { DeviceType } from "@bitwarden/device-type"; + +interface ToastOptions { + timeout?: number; +} + +export type ClipboardOptions = { + allowHistory?: boolean; + clearing?: boolean; + clearMs?: number; + window?: Window; +}; + +export abstract class PlatformUtilsService { + abstract getDevice(): DeviceType; + abstract getDeviceString(): string; + abstract getClientType(): ClientType; + abstract isFirefox(): boolean; + abstract isChrome(): boolean; + abstract isEdge(): boolean; + abstract isOpera(): boolean; + abstract isVivaldi(): boolean; + abstract isSafari(): boolean; + abstract isMacAppStore(): boolean; + abstract isViewOpen(): Promise; + abstract launchUri(uri: string, options?: any): void; + abstract getApplicationVersion(): Promise; + abstract getApplicationVersionNumber(): Promise; + abstract supportsWebAuthn(win: Window): boolean; + abstract supportsDuo(): boolean; + /** + * Returns true if the device supports autofill functionality + */ + abstract supportsAutofill(): boolean; + /** + * Returns true if the device supports native file downloads without + * the need for `target="_blank"` + */ + abstract supportsFileDownloads(): boolean; + /** + * @deprecated use `@bitwarden/components/ToastService.showToast` instead + * + * Jira: [CL-213](https://bitwarden.atlassian.net/browse/CL-213) + */ + abstract showToast( + type: "error" | "success" | "warning" | "info", + title: string, + text: string | string[], + options?: ToastOptions, + ): void; + abstract isDev(): boolean; + abstract isSelfHost(): boolean; + abstract copyToClipboard(text: string, options?: ClipboardOptions): void | boolean; + abstract readFromClipboard(): Promise; + abstract supportsSecureStorage(): boolean; + abstract getAutofillKeyboardShortcut(): Promise; +} diff --git a/libs/platform-utils/src/platform-utils.service.ts b/libs/platform-utils/src/platform-utils.service.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libs/platform-utils/src/platform-utils.spec.ts b/libs/platform-utils/src/platform-utils.spec.ts new file mode 100644 index 00000000000..f0612a62b35 --- /dev/null +++ b/libs/platform-utils/src/platform-utils.spec.ts @@ -0,0 +1,8 @@ +import * as lib from "./index"; + +describe("platform-utils", () => { + // This test will fail until something is exported from index.ts + it("should work", () => { + expect(lib).toBeDefined(); + }); +}); diff --git a/libs/platform-utils/tsconfig.eslint.json b/libs/platform-utils/tsconfig.eslint.json new file mode 100644 index 00000000000..3daf120441a --- /dev/null +++ b/libs/platform-utils/tsconfig.eslint.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": ["src/**/*.ts", "src/**/*.js"], + "exclude": ["**/build", "**/dist"] +} diff --git a/libs/platform-utils/tsconfig.json b/libs/platform-utils/tsconfig.json new file mode 100644 index 00000000000..62ebbd94647 --- /dev/null +++ b/libs/platform-utils/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/platform-utils/tsconfig.lib.json b/libs/platform-utils/tsconfig.lib.json new file mode 100644 index 00000000000..9cbf6736007 --- /dev/null +++ b/libs/platform-utils/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.js", "src/**/*.spec.ts"] +} diff --git a/libs/platform-utils/tsconfig.spec.json b/libs/platform-utils/tsconfig.spec.json new file mode 100644 index 00000000000..1275f148a18 --- /dev/null +++ b/libs/platform-utils/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "moduleResolution": "node10", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/libs/token-provider/src/device.request.ts b/libs/token-provider/src/device.request.ts new file mode 100644 index 00000000000..5b7df6c9f4b --- /dev/null +++ b/libs/token-provider/src/device.request.ts @@ -0,0 +1,25 @@ +// FIXME: Update this file to be type safe and remove this and next line +// @ts-strict-ignore +import { Jsonify } from "type-fest"; + +import { DeviceType } from "@bitwarden/device-type"; + +import { PlatformUtilsService } from "../../../../platform/abstractions/platform-utils.service"; + +export class DeviceRequest { + type: DeviceType; + name: string; + identifier: string; + pushToken?: string; + + constructor(appId: string, platformUtilsService: PlatformUtilsService) { + this.type = platformUtilsService.getDevice(); + this.name = platformUtilsService.getDeviceString(); + this.identifier = appId; + this.pushToken = null; + } + + static fromJSON(json: Jsonify) { + return Object.assign(Object.create(DeviceRequest.prototype), json); + } +} diff --git a/package-lock.json b/package-lock.json index 5c6e44eac0a..914af85c221 100644 --- a/package-lock.json +++ b/package-lock.json @@ -402,6 +402,11 @@ "version": "0.0.0", "license": "GPL-3.0" }, + "libs/platform-utils": { + "name": "@bitwarden/platform-utils", + "version": "0.0.1", + "license": "GPL-3.0" + }, "libs/serialization": { "name": "@bitwarden/serialization", "version": "0.0.1", @@ -4681,6 +4686,10 @@ "resolved": "libs/platform", "link": true }, + "node_modules/@bitwarden/platform-utils": { + "resolved": "libs/platform-utils", + "link": true + }, "node_modules/@bitwarden/sdk-internal": { "version": "0.2.0-main.242", "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.242.tgz", diff --git a/tsconfig.base.json b/tsconfig.base.json index 93bc31a38da..26a5a041ca3 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -48,6 +48,7 @@ "@bitwarden/node/*": ["./libs/node/src/*"], "@bitwarden/nx-plugin": ["libs/nx-plugin/src/index.ts"], "@bitwarden/platform": ["./libs/platform/src"], + "@bitwarden/platform-utils": ["libs/platform-utils/src/index.ts"], "@bitwarden/platform/*": ["./libs/platform/src/*"], "@bitwarden/send-ui": ["./libs/tools/send/send-ui/src"], "@bitwarden/serialization": ["libs/serialization/src/index.ts"],