From 2bd191e25546a87dfcd8c96f8d29ef591e7ba806 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Sun, 6 Jul 2025 14:41:20 -0600 Subject: [PATCH] Move remaining strings for Environment & Platform to type-checked values. --- .env.dev => .env.development | 0 .env.prod => .env.production | 0 .env.test => .env.testing | 0 index.html | 12 ++++--- package.json | 4 +-- src/electron/preload.js | 13 +++---- src/interfaces/build.ts | 21 ++++++++++++ src/main.web.ts | 6 ++-- src/registerServiceWorker.ts | 5 +-- src/services/PlatformServiceFactory.ts | 11 +++--- src/services/api.ts | 3 +- src/utils/logger.ts | 13 +++---- src/views/DeepLinkRedirectView.vue | 3 +- tsconfig.node.json | 2 +- vite.config.capacitor.mts | 3 +- vite.config.common.mts | 47 +++++++++++++------------- vite.config.electron.mts | 3 +- vite.config.pywebview.mts | 3 +- vite.config.web.mts | 3 +- 19 files changed, 95 insertions(+), 57 deletions(-) rename .env.dev => .env.development (100%) rename .env.prod => .env.production (100%) rename .env.test => .env.testing (100%) create mode 100644 src/interfaces/build.ts diff --git a/.env.dev b/.env.development similarity index 100% rename from .env.dev rename to .env.development diff --git a/.env.prod b/.env.production similarity index 100% rename from .env.prod rename to .env.production diff --git a/.env.test b/.env.testing similarity index 100% rename from .env.test rename to .env.testing diff --git a/index.html b/index.html index ea64cda3..5a583580 100644 --- a/index.html +++ b/index.html @@ -15,17 +15,21 @@ diff --git a/package.json b/package.json index d7972df1..9f7ec9ce 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,10 @@ "build:electron": "npm run clean:electron && tsc -p tsconfig.electron.json && vite build --config vite.config.electron.mts && node scripts/build-electron.js", "build:electron-linux": "npm run build:electron && electron-builder --linux AppImage", "build:electron-linux-deb": "npm run build:electron && electron-builder --linux deb", - "build:electron-linux-prod": "NODE_ENV=production npm run build:electron && electron-builder --linux AppImage", + "build:electron-linux-prod": "NODE_ENV=prod npm run build:electron && electron-builder --linux AppImage", "build:electron-mac": "npm run build:electron-prod && electron-builder --mac", "build:electron-mac-universal": "npm run build:electron-prod && electron-builder --mac --universal", - "build:electron-prod": "NODE_ENV=production npm run build:electron", + "build:electron-prod": "NODE_ENV=prod npm run build:electron", "build:pywebview": "vite build --config vite.config.pywebview.mts", "build:web": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts", "check:android-device": "adb devices | grep -w 'device' || (echo 'No Android device connected' && exit 1)", diff --git a/src/electron/preload.js b/src/electron/preload.js index 2b37f099..efe49fb1 100644 --- a/src/electron/preload.js +++ b/src/electron/preload.js @@ -1,9 +1,10 @@ const { contextBridge, ipcRenderer } = require("electron"); +import { NodeEnv, BuildPlatform } from "@/interfaces/build"; const logger = { log: (message, ...args) => { // Always log in development, log with context in production - if (process.env.NODE_ENV !== "production") { + if (process.env.NODE_ENV !== NodeEnv.Prod) { /* eslint-disable no-console */ console.log(`[Preload] ${message}`, ...args); /* eslint-enable no-console */ @@ -23,7 +24,7 @@ const logger = { }, info: (message, ...args) => { // Always log info in development, log with context in production - if (process.env.NODE_ENV !== "production") { + if (process.env.NODE_ENV !== NodeEnv.Prod) { /* eslint-disable no-console */ console.info(`[Preload] ${message}`, ...args); /* eslint-enable no-console */ @@ -53,7 +54,7 @@ const getPath = (pathType) => { logger.info("Preload script starting..."); // Force electron platform in the renderer process -window.process = { env: { VITE_PLATFORM: "electron" } }; +window.process = { env: { VITE_PLATFORM: BuildPlatform.Electron } }; try { contextBridge.exposeInMainWorld("electronAPI", { @@ -76,12 +77,12 @@ try { // Environment info env: { isElectron: true, - isDev: process.env.NODE_ENV === "development", - platform: "electron", // Explicitly set platform + isDev: process.env.NODE_ENV === NodeEnv.Dev, + platform: BuildPlatform.Electron, // Explicitly set platform }, // Path utilities getBasePath: () => { - return process.env.NODE_ENV === "development" ? "/" : "./"; + return process.env.NODE_ENV === NodeEnv.Dev ? "/" : "./"; }, }); diff --git a/src/interfaces/build.ts b/src/interfaces/build.ts new file mode 100644 index 00000000..133356f1 --- /dev/null +++ b/src/interfaces/build.ts @@ -0,0 +1,21 @@ +export const NodeEnv = { + Dev: "dev", + Test: "test", + Prod: "prod", +} as const; +export type NodeEnv = typeof NodeEnv[keyof typeof NodeEnv]; + +export const BuildEnv = { + Development: "development", + Testing: "testing", + Production: "production", +} as const; +export type BuildEnv = typeof BuildEnv[keyof typeof BuildEnv]; + +export const BuildPlatform = { + Web: "web", + Electron: "electron", + Capacitor: "capacitor", + PyWebView: "pywebview", +} as const; +export type BuildPlatform = typeof BuildPlatform[keyof typeof BuildPlatform]; diff --git a/src/main.web.ts b/src/main.web.ts index ff149056..60435763 100644 --- a/src/main.web.ts +++ b/src/main.web.ts @@ -1,12 +1,14 @@ import { initBackend } from "absurd-sql/dist/indexeddb-main-thread"; + import { initializeApp } from "./main.common"; import { logger } from "./utils/logger"; +import { BuildPlatform } from "@/interfaces/build"; const platform = process.env.VITE_PLATFORM; const pwa_enabled = process.env.VITE_PWA_ENABLED === "true"; // Only import service worker for web builds -if (platform !== "electron" && pwa_enabled) { +if (platform !== BuildPlatform.Electron && pwa_enabled) { import("./registerServiceWorker"); // Web PWA support } @@ -25,7 +27,7 @@ function sqlInit() { // workers through the main thread initBackend(worker); } -if (platform === "web" || platform === "development") { +if (platform === BuildPlatform.Web) { sqlInit(); } else { logger.warn("[Web] SQL not initialized for platform", { platform }); diff --git a/src/registerServiceWorker.ts b/src/registerServiceWorker.ts index e1f328b8..57153122 100644 --- a/src/registerServiceWorker.ts +++ b/src/registerServiceWorker.ts @@ -1,10 +1,11 @@ /* eslint-disable no-console */ import { register } from "register-service-worker"; +import { NodeEnv, BuildPlatform } from "@/interfaces/build"; // Check if we're in an Electron environment const isElectron = - process.env.VITE_PLATFORM === "electron" || + process.env.VITE_PLATFORM === BuildPlatform.Electron || process.env.VITE_DISABLE_PWA === "true" || window.navigator.userAgent.toLowerCase().includes("electron"); @@ -15,7 +16,7 @@ const isElectron = if ( !isElectron && process.env.VITE_PWA_ENABLED === "true" && - process.env.NODE_ENV === "production" + process.env.NODE_ENV === NodeEnv.Prod ) { register(`${process.env.BASE_URL}sw.js`, { ready() { diff --git a/src/services/PlatformServiceFactory.ts b/src/services/PlatformServiceFactory.ts index f5e34fa2..cef4324a 100644 --- a/src/services/PlatformServiceFactory.ts +++ b/src/services/PlatformServiceFactory.ts @@ -3,6 +3,7 @@ import { WebPlatformService } from "./platforms/WebPlatformService"; import { CapacitorPlatformService } from "./platforms/CapacitorPlatformService"; import { ElectronPlatformService } from "./platforms/ElectronPlatformService"; import { PyWebViewPlatformService } from "./platforms/PyWebViewPlatformService"; +import { BuildPlatform } from "@/interfaces/build"; /** * Factory class for creating platform-specific service implementations. @@ -35,19 +36,19 @@ export class PlatformServiceFactory { return PlatformServiceFactory.instance; } - const platform = process.env.VITE_PLATFORM || "web"; + const platform = process.env.VITE_PLATFORM || BuildPlatform.Web; switch (platform) { - case "capacitor": + case BuildPlatform.Capacitor: PlatformServiceFactory.instance = new CapacitorPlatformService(); break; - case "electron": + case BuildPlatform.Electron: PlatformServiceFactory.instance = new ElectronPlatformService(); break; - case "pywebview": + case BuildPlatform.PyWebView: PlatformServiceFactory.instance = new PyWebViewPlatformService(); break; - case "web": + case BuildPlatform.Web: default: PlatformServiceFactory.instance = new WebPlatformService(); break; diff --git a/src/services/api.ts b/src/services/api.ts index d7b67beb..93a2b691 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -7,6 +7,7 @@ import { AxiosError } from "axios"; import { logger, safeStringify } from "../utils/logger"; +import { BuildPlatform } from "@/interfaces/build"; /** * Handles API errors with platform-specific logging and error processing. @@ -36,7 +37,7 @@ import { logger, safeStringify } from "../utils/logger"; * ``` */ export const handleApiError = (error: AxiosError, endpoint: string) => { - if (process.env.VITE_PLATFORM === "capacitor") { + if (process.env.VITE_PLATFORM === BuildPlatform.Capacitor) { const endpointStr = safeStringify(endpoint); // we've seen this as an object in deep links logger.error(`[Capacitor API Error] ${endpointStr}:`, { message: error.message, diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 8184c28b..ecca19f7 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,4 +1,5 @@ import { logToDb } from "../db/databaseUtil"; +import { BuildPlatform, NodeEnv } from "@/interfaces/build"; export function safeStringify(obj: unknown) { const seen = new WeakSet(); @@ -21,7 +22,7 @@ export function safeStringify(obj: unknown) { export const logger = { debug: (message: string, ...args: unknown[]) => { - if (process.env.NODE_ENV !== "production") { + if (process.env.NODE_ENV !== NodeEnv.Prod) { // eslint-disable-next-line no-console console.debug(message, ...args); // const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; @@ -30,8 +31,8 @@ export const logger = { }, log: (message: string, ...args: unknown[]) => { if ( - process.env.NODE_ENV !== "production" || - process.env.VITE_PLATFORM === "capacitor" + process.env.NODE_ENV !== NodeEnv.Prod || + process.env.VITE_PLATFORM === BuildPlatform.Capacitor ) { // eslint-disable-next-line no-console console.log(message, ...args); @@ -41,9 +42,9 @@ export const logger = { }, info: (message: string, ...args: unknown[]) => { if ( - process.env.NODE_ENV !== "production" || - process.env.VITE_PLATFORM === "capacitor" || - process.env.VITE_PLATFORM === "electron" + process.env.NODE_ENV !== NodeEnv.Prod || + process.env.VITE_PLATFORM === BuildPlatform.Capacitor || + process.env.VITE_PLATFORM === BuildPlatform.Electron ) { // eslint-disable-next-line no-console console.info(message, ...args); diff --git a/src/views/DeepLinkRedirectView.vue b/src/views/DeepLinkRedirectView.vue index 8d2cb08c..71dd1a2f 100644 --- a/src/views/DeepLinkRedirectView.vue +++ b/src/views/DeepLinkRedirectView.vue @@ -100,6 +100,7 @@ import { Component, Vue } from "vue-facing-decorator"; import { RouteLocationNormalizedLoaded, Router } from "vue-router"; import { APP_SERVER } from "@/constants/app"; +import { NodeEnv } from "@/interfaces/build"; import { logger } from "@/utils/logger"; import { errorStringForLog } from "@/libs/endorserServer"; import { PlatformServiceFactory } from "@/services/PlatformServiceFactory"; @@ -148,7 +149,7 @@ export default class DeepLinkRedirectView extends Vue { this.deepLinkUrl = `timesafari://${fullPathWithQuery}`; this.webUrl = `${APP_SERVER}/${fullPathWithQuery}`; - this.isDevelopment = process.env.NODE_ENV !== "production"; + this.isDevelopment = process.env.NODE_ENV !== NodeEnv.Prod; this.userAgent = navigator.userAgent; this.openDeepLink(); diff --git a/tsconfig.node.json b/tsconfig.node.json index f2bdbb1d..ca790e95 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -8,5 +8,5 @@ "allowImportingTsExtensions": true, "noEmit": true }, - "include": ["vite.config.*"] + "include": ["vite.config.*", "./src/interfaces/build.ts"] } \ No newline at end of file diff --git a/vite.config.capacitor.mts b/vite.config.capacitor.mts index b47e5abe..a72f9b29 100644 --- a/vite.config.capacitor.mts +++ b/vite.config.capacitor.mts @@ -1,4 +1,5 @@ import { defineConfig } from "vite"; import { createBuildConfig } from "./vite.config.common.mts"; +import { BuildPlatform } from "./src/interfaces/build.ts"; -export default defineConfig(async () => createBuildConfig('capacitor')); \ No newline at end of file +export default defineConfig(async () => createBuildConfig(BuildPlatform.Capacitor)); \ No newline at end of file diff --git a/vite.config.common.mts b/vite.config.common.mts index e87b3ba7..eb8bac56 100644 --- a/vite.config.common.mts +++ b/vite.config.common.mts @@ -1,39 +1,40 @@ -import { defineConfig, UserConfig, Plugin } from "vite"; +import { defineConfig, UserConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import dotenv from "dotenv"; import { loadAppConfig } from "./vite.config.common-utils.mts"; import path from "path"; import { fileURLToPath } from 'url'; - -export type BuildMode = 'web' | 'electron' | 'capacitor' | 'pywebview'; -export type BuildEnv = 'dev' | 'test' | 'prod'; +import { NodeEnv, BuildEnv, BuildPlatform } from "./src/interfaces/build.ts"; // Load environment variables -if ( - process.env.NODE_ENV === 'dev' - || process.env.NODE_ENV === 'test' - || process.env.NODE_ENV === 'prod' - ) { - console.log(`NODE_ENV=${process.env.NODE_ENV}`); +let buildEnv: BuildEnv; +if (process.env.NODE_ENV === NodeEnv.Dev) { + buildEnv = BuildEnv.Development; +} else if (process.env.NODE_ENV === NodeEnv.Test) { + buildEnv = BuildEnv.Testing; +} else if (process.env.NODE_ENV === NodeEnv.Prod) { + buildEnv = BuildEnv.Production; } else { - console.error("NODE_ENV is not set. Invoke with NODE_ENV=dev|test|prod"); - throw new Error("NODE_ENV is not set. Invoke with NODE_ENV=dev|test|prod"); - // process.exit(1); + console.error("NODE_ENV is not set. Invoke with NODE_ENV=" + Object.values(NodeEnv).join("|")); + throw new Error("NODE_ENV is not set. Invoke with NODE_ENV=" + Object.values(NodeEnv).join("|")); } +console.log(`Environment: ${buildEnv}`); -dotenv.config({ path: `.env.${process.env.NODE_ENV}` }); +dotenv.config({ path: `.env.${buildEnv}` }); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -export async function createBuildConfig(mode: BuildMode): Promise { +export async function createBuildConfig(platform: BuildPlatform): Promise { const appConfig = await loadAppConfig(); - const isElectron = mode === "electron"; - const isCapacitor = mode === "capacitor"; - const isPyWebView = mode === "pywebview"; + + console.log(`Platform: ${platform}`); + const isElectron = platform === BuildPlatform.Electron; + const isCapacitor = platform === BuildPlatform.Capacitor; + const isPyWebView = platform === BuildPlatform.PyWebView; // Explicitly set platform and disable PWA for Electron - process.env.VITE_PLATFORM = mode; + process.env.VITE_PLATFORM = platform; process.env.VITE_PWA_ENABLED = (isElectron || isPyWebView || isCapacitor) ? 'false' : 'true'; @@ -69,7 +70,7 @@ export async function createBuildConfig(mode: BuildMode): Promise { }, define: { 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), - 'process.env.VITE_PLATFORM': JSON.stringify(mode), + 'process.env.VITE_PLATFORM': JSON.stringify(platform), 'process.env.VITE_PWA_ENABLED': JSON.stringify(!isElectron), 'process.env.VITE_DISABLE_PWA': JSON.stringify(isElectron), __dirname: isElectron ? JSON.stringify(process.cwd()) : '""', @@ -91,10 +92,10 @@ export async function createBuildConfig(mode: BuildMode): Promise { 'path': path.resolve(__dirname, './src/utils/node-modules/path.js'), 'fs': path.resolve(__dirname, './src/utils/node-modules/fs.js'), 'crypto': path.resolve(__dirname, './src/utils/node-modules/crypto.js'), - 'nostr-tools/nip06': mode === 'development' + 'nostr-tools/nip06': buildEnv === BuildEnv.Development ? 'nostr-tools/nip06' : path.resolve(__dirname, 'node_modules/nostr-tools/nip06'), - 'nostr-tools/core': mode === 'development' + 'nostr-tools/core': buildEnv === BuildEnv.Development ? 'nostr-tools' : path.resolve(__dirname, 'node_modules/nostr-tools'), 'nostr-tools': path.resolve(__dirname, 'node_modules/nostr-tools'), @@ -121,4 +122,4 @@ export async function createBuildConfig(mode: BuildMode): Promise { }; } -export default defineConfig(async () => createBuildConfig('web')); +export default defineConfig(async () => createBuildConfig(BuildPlatform.Web)); diff --git a/vite.config.electron.mts b/vite.config.electron.mts index 07188939..f966370f 100644 --- a/vite.config.electron.mts +++ b/vite.config.electron.mts @@ -1,9 +1,10 @@ import { defineConfig, mergeConfig } from "vite"; import { createBuildConfig } from "./vite.config.common.mts"; import path from 'path'; +import { BuildPlatform } from "./src/interfaces/build.ts"; export default defineConfig(async () => { - const baseConfig = await createBuildConfig('electron'); + const baseConfig = await createBuildConfig(BuildPlatform.Electron); return mergeConfig(baseConfig, { build: { diff --git a/vite.config.pywebview.mts b/vite.config.pywebview.mts index 81892137..f6371e9f 100644 --- a/vite.config.pywebview.mts +++ b/vite.config.pywebview.mts @@ -1,4 +1,5 @@ import { defineConfig } from "vite"; import { createBuildConfig } from "./vite.config.common.mts"; +import { BuildPlatform } from "./src/interfaces/build.ts"; -export default defineConfig(async () => createBuildConfig('pywebview')); \ No newline at end of file +export default defineConfig(async () => createBuildConfig(BuildPlatform.PyWebView)); \ No newline at end of file diff --git a/vite.config.web.mts b/vite.config.web.mts index a2f987f2..33a78784 100644 --- a/vite.config.web.mts +++ b/vite.config.web.mts @@ -2,9 +2,10 @@ import { defineConfig, mergeConfig } from "vite"; import { VitePWA } from "vite-plugin-pwa"; import { createBuildConfig } from "./vite.config.common.mts"; import { loadPwaConfig } from "./vite.config.common-utils.mts"; +import { BuildPlatform } from "./src/interfaces/build.ts"; export default defineConfig(async () => { - const baseConfig = await createBuildConfig('web'); + const baseConfig = await createBuildConfig(BuildPlatform.Web); const pwaConfig = await loadPwaConfig(); return mergeConfig(baseConfig, {