chore: remove hoppscotch-web from self-hosted

This commit is contained in:
Andrew Bastin
2023-04-11 18:31:08 +05:30
parent b68115d3b2
commit a8f0a8a253
19 changed files with 0 additions and 2355 deletions

View File

@@ -1,64 +0,0 @@
/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution")
module.exports = {
root: true,
env: {
browser: true,
node: true,
jest: true,
},
parserOptions: {
sourceType: "module",
requireConfigFile: false,
},
extends: [
"@vue/typescript/recommended",
"plugin:vue/vue3-recommended",
"plugin:prettier/recommended",
],
ignorePatterns: [
"static/**/*",
"./helpers/backend/graphql.ts",
"**/*.d.ts",
"types/**/*",
],
plugins: ["vue", "prettier"],
// add your custom rules here
rules: {
semi: [2, "never"],
"import/named": "off", // because, named import issue with typescript see: https://github.com/typescript-eslint/typescript-eslint/issues/154
"no-console": "off",
"no-debugger": process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn",
"prettier/prettier":
process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn",
"vue/multi-word-component-names": "off",
"vue/no-side-effects-in-computed-properties": "off",
"import/no-named-as-default": "off",
"import/no-named-as-default-member": "off",
"@typescript-eslint/no-unused-vars":
process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
"import/default": "off",
"no-undef": "off",
// localStorage block
"no-restricted-globals": [
"error",
{
name: "localStorage",
message:
"Do not use 'localStorage' directly. Please use localpersistence.ts functions or stores",
},
],
// window.localStorage block
"no-restricted-syntax": [
"error",
{
selector: "CallExpression[callee.object.property.name='localStorage']",
message:
"Do not use 'localStorage' directly. Please use localpersistence.ts functions or stores",
},
],
},
}

View File

@@ -1,27 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Sitemap Generation Artifacts (see vite.config.ts)
.sitemap-gen

View File

@@ -1,26 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hoppscotch • Open source API development ecosystem</title>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="apple-touch-icon" href="/icon.png" />
</head>
<body>
<div id="app"></div>
<script>
// Shims to make swagger-parser package work
window.global = window
</script>
<script type="module">
import { Buffer } from "buffer"
import process from "process"
// // Shims to make postman-collection work
window.Buffer = Buffer
window.process = process
</script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -1,118 +0,0 @@
import { IHTMLTag } from "vite-plugin-html-config"
export const APP_INFO = {
name: "Hoppscotch",
shortDescription: "Open source API development ecosystem",
description:
"Helps you create requests faster, saving precious time on development.",
keywords:
"hoppscotch, hopp scotch, hoppscotch online, hoppscotch app, postwoman, postwoman chrome, postwoman online, postwoman for mac, postwoman app, postwoman for windows, postwoman google chrome, postwoman chrome app, get postwoman, postwoman web, postwoman android, postwoman app for chrome, postwoman mobile app, postwoman web app, api, request, testing, tool, rest, websocket, sse, graphql, socketio",
app: {
background: "#202124",
},
social: {
twitter: "@hoppscotch_io",
},
} as const
export const META_TAGS = (env: Record<string, string>): IHTMLTag[] => [
{
name: "keywords",
content: APP_INFO.keywords,
},
{
name: "X-UA-Compatible",
content: "IE=edge, chrome=1",
},
{
name: "name",
content: `${APP_INFO.name}${APP_INFO.shortDescription}`,
},
{
name: "description",
content: APP_INFO.description,
},
{
name: "image",
content: `${env.VITE_BASE_URL}/banner.png`,
},
// Open Graph tags
{
name: "og:title",
content: `${APP_INFO.name}${APP_INFO.shortDescription}`,
},
{
name: "og:description",
content: APP_INFO.description,
},
{
name: "og:image",
content: `${env.VITE_BASE_URL}/banner.png`,
},
// Twitter tags
{
name: "twitter:card",
content: "summary_large_image",
},
{
name: "twitter:site",
content: APP_INFO.social.twitter,
},
{
name: "twitter:creator",
content: APP_INFO.social.twitter,
},
{
name: "twitter:title",
content: `${APP_INFO.name}${APP_INFO.shortDescription}`,
},
{
name: "twitter:description",
content: APP_INFO.description,
},
{
name: "twitter:image",
content: `${env.VITE_BASE_URL}/banner.png`,
},
// Add to homescreen for Chrome on Android. Fallback for PWA (handled by nuxt)
{
name: "application-name",
content: APP_INFO.name,
},
// Windows phone tile icon
{
name: "msapplication-TileImage",
content: `${env.VITE_BASE_URL}/icon.png`,
},
{
name: "msapplication-TileColor",
content: APP_INFO.app.background,
},
{
name: "msapplication-tap-highlight",
content: "no",
},
// iOS Safari
{
name: "apple-mobile-web-app-title",
content: APP_INFO.name,
},
{
name: "apple-mobile-web-app-capable",
content: "yes",
},
{
name: "apple-mobile-web-app-status-bar-style",
content: "black-translucent",
},
// PWA
{
name: "theme-color",
content: APP_INFO.app.background,
},
{
name: "mask-icon",
content: "/icon.png",
color: APP_INFO.app.background,
},
]

View File

@@ -1,62 +0,0 @@
{
"name": "@hoppscotch/web",
"private": true,
"version": "2023.4.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "node --max_old_space_size=16384 ./node_modules/vite/bin/vite.js build",
"preview": "vite preview",
"lint": "eslint src --ext .ts,.js,.vue --ignore-path .gitignore .",
"lint:ts": "vue-tsc --noEmit",
"lintfix": "eslint --fix src --ext .ts,.js,.vue --ignore-path .gitignore .",
"prod-lint": "cross-env HOPP_LINT_FOR_PROD=true pnpm run lint",
"generate": "pnpm run build",
"do-dev": "pnpm run dev",
"do-build-prod": "pnpm run build",
"do-lint": "pnpm run prod-lint",
"do-typecheck": "pnpm run lint",
"do-lintfix": "pnpm run lintfix"
},
"dependencies": {
"@hoppscotch/common": "workspace:^",
"@hoppscotch/ui": "workspace:^",
"buffer": "^6.0.3",
"firebase": "^9.8.4",
"process": "^0.11.10",
"rxjs": "^7.5.5",
"stream-browserify": "^3.0.0",
"util": "^0.12.4",
"vue": "^3.2.41",
"workbox-window": "^6.5.4",
"@hoppscotch/data": "workspace:^"
},
"devDependencies": {
"@intlify/vite-plugin-vue-i18n": "^6.0.1",
"@rushstack/eslint-patch": "^1.1.4",
"@typescript-eslint/eslint-plugin": "^5.19.0",
"@typescript-eslint/parser": "^5.19.0",
"@vitejs/plugin-legacy": "^2.3.0",
"@vitejs/plugin-vue": "^3.2.0",
"@vue/eslint-config-typescript": "^11.0.1",
"cross-env": "^7.0.3",
"eslint": "^8.28.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.5.1",
"typescript": "^4.6.4",
"unplugin-icons": "^0.14.9",
"unplugin-vue-components": "^0.21.0",
"vite": "^3.2.3",
"vite-plugin-fonts": "^0.6.0",
"vite-plugin-html-config": "^1.0.10",
"vite-plugin-inspect": "^0.7.4",
"vite-plugin-pages": "^0.26.0",
"vite-plugin-pages-sitemap": "^1.4.0",
"vite-plugin-pwa": "^0.13.1",
"vite-plugin-static-copy": "^0.12.0",
"vite-plugin-vue-layouts": "^0.7.0",
"vite-plugin-windicss": "^1.8.8",
"vue-tsc": "^1.0.9",
"windicss": "^3.5.6"
}
}

View File

@@ -1,113 +0,0 @@
import {
AnalyticsPlatformDef,
HoppRequestEvent,
} from "@hoppscotch/common/platform/analytics"
import {
Analytics,
getAnalytics,
logEvent,
setAnalyticsCollectionEnabled,
setUserId,
setUserProperties,
} from "firebase/analytics"
import { def as platformAuth } from "./firebase/auth"
import {
HoppAccentColor,
HoppBgColor,
settings$,
settingsStore,
} from "@hoppscotch/common/newstore/settings"
let analytics: Analytics | null = null
type SettingsCustomDimensions = {
usesProxy: boolean
usesExtension: boolean
syncCollections: boolean
syncEnvironments: boolean
syncHistory: boolean
usesBg: HoppBgColor
usesAccent: HoppAccentColor
usesTelemetry: boolean
}
export function initAnalytics() {
analytics = getAnalytics()
initLoginListeners()
initSettingsListeners()
}
function initLoginListeners() {
const authEvents$ = platformAuth.getAuthEventsStream()
authEvents$.subscribe((ev) => {
if (ev.event === "login") {
if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
setUserId(analytics, ev.user.uid)
logEvent(analytics, "login", {
method: ev.user.provider, // Assume the first provider is the login provider
})
}
} else if (ev.event === "logout") {
if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
logEvent(analytics, "logout")
}
}
})
}
function initSettingsListeners() {
// Keep track of the telemetry status
let telemetryStatus = settingsStore.value.TELEMETRY_ENABLED
settings$.subscribe((settings) => {
const conf: SettingsCustomDimensions = {
usesProxy: settings.PROXY_ENABLED,
usesExtension: settings.EXTENSIONS_ENABLED,
syncCollections: settings.syncCollections,
syncEnvironments: settings.syncEnvironments,
syncHistory: settings.syncHistory,
usesAccent: settings.THEME_COLOR,
usesBg: settings.BG_COLOR,
usesTelemetry: settings.TELEMETRY_ENABLED,
}
// User toggled telemetry mode to off or to on
if (
((telemetryStatus && !settings.TELEMETRY_ENABLED) ||
settings.TELEMETRY_ENABLED) &&
analytics
) {
setUserProperties(analytics, conf)
}
telemetryStatus = settings.TELEMETRY_ENABLED
if (analytics) setAnalyticsCollectionEnabled(analytics, telemetryStatus)
})
if (analytics) setAnalyticsCollectionEnabled(analytics, telemetryStatus)
}
export function logHoppRequestRunToAnalytics(ev: HoppRequestEvent) {
if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
logEvent(analytics, "hopp-request", ev)
}
}
export function logPageView(pagePath: string) {
if (settingsStore.value.TELEMETRY_ENABLED && analytics) {
logEvent(analytics, "page_view", {
page_path: pagePath,
})
}
}
export const def: AnalyticsPlatformDef = {
initAnalytics,
logHoppRequestRunToAnalytics,
logPageView,
}

View File

@@ -1,193 +0,0 @@
import {
collection,
doc,
getFirestore,
onSnapshot,
setDoc,
} from "firebase/firestore"
import {
translateToNewRESTCollection,
translateToNewGQLCollection,
} from "@hoppscotch/data"
import { def as platformAuth } from "./firebase/auth"
import {
restCollections$,
graphqlCollections$,
setRESTCollections,
setGraphqlCollections,
} from "@hoppscotch/common/newstore/collections"
import {
getSettingSubject,
settingsStore,
} from "@hoppscotch/common/newstore/settings"
import { CollectionsPlatformDef } from "@hoppscotch/common/platform/collections"
type CollectionFlags = "collectionsGraphql" | "collections"
/**
* Whether the collections are loaded. If this is set to true
* Updates to the collections store are written into firebase.
*
* If you have want to update the store and not fire the store update
* subscription, set this variable to false, do the update and then
* set it to true
*/
let loadedRESTCollections = false
/**
* Whether the collections are loaded. If this is set to true
* Updates to the collections store are written into firebase.
*
* If you have want to update the store and not fire the store update
* subscription, set this variable to false, do the update and then
* set it to true
*/
let loadedGraphqlCollections = false
async function writeCollections(collection: any[], flag: CollectionFlags) {
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("User not logged in to write collections")
const cl = {
updatedOn: new Date(),
author: currentUser.uid,
author_name: currentUser.displayName,
author_image: currentUser.photoURL,
collection,
}
try {
await setDoc(
doc(getFirestore(), "users", currentUser.uid, flag, "sync"),
cl
)
} catch (e) {
console.error("error updating", cl, e)
throw e
}
}
function initCollectionsSync() {
const currentUser$ = platformAuth.getCurrentUserStream()
const restCollSub = restCollections$.subscribe((collections) => {
const currentUser = platformAuth.getCurrentUser()
if (
loadedRESTCollections &&
currentUser &&
settingsStore.value.syncCollections
) {
writeCollections(collections, "collections")
}
})
const gqlCollSub = graphqlCollections$.subscribe((collections) => {
const currentUser = platformAuth.getCurrentUser()
if (
loadedGraphqlCollections &&
currentUser &&
settingsStore.value.syncCollections
) {
writeCollections(collections, "collectionsGraphql")
}
})
let restSnapshotStop: (() => void) | null = null
let graphqlSnapshotStop: (() => void) | null = null
const currentUserSub = currentUser$.subscribe((user) => {
if (!user) {
if (restSnapshotStop) {
restSnapshotStop()
restSnapshotStop = null
}
if (graphqlSnapshotStop) {
graphqlSnapshotStop()
graphqlSnapshotStop = null
}
} else {
restSnapshotStop = onSnapshot(
collection(getFirestore(), "users", user.uid, "collections"),
(collectionsRef) => {
const collections: any[] = []
collectionsRef.forEach((doc) => {
const collection = doc.data()
collection.id = doc.id
collections.push(collection)
})
// Prevent infinite ping-pong of updates
loadedRESTCollections = false
// TODO: Wth is with collections[0]
if (collections.length > 0 && settingsStore.value.syncCollections) {
setRESTCollections(
(collections[0].collection ?? []).map(
translateToNewRESTCollection
)
)
}
loadedRESTCollections = true
}
)
graphqlSnapshotStop = onSnapshot(
collection(getFirestore(), "users", user.uid, "collectionsGraphql"),
(collectionsRef) => {
const collections: any[] = []
collectionsRef.forEach((doc) => {
const collection = doc.data()
collection.id = doc.id
collections.push(collection)
})
// Prevent infinite ping-pong of updates
loadedGraphqlCollections = false
// TODO: Wth is with collections[0]
if (collections.length > 0 && settingsStore.value.syncCollections) {
setGraphqlCollections(
(collections[0].collection ?? []).map(translateToNewGQLCollection)
)
}
loadedGraphqlCollections = true
}
)
}
})
let oldSyncStatus = settingsStore.value.syncCollections
const syncStop = getSettingSubject("syncCollections").subscribe(
(newStatus) => {
if (oldSyncStatus === true && newStatus === false) {
restSnapshotStop?.()
graphqlSnapshotStop?.()
oldSyncStatus = newStatus
} else if (oldSyncStatus === false && newStatus === true) {
syncStop.unsubscribe()
restCollSub.unsubscribe()
gqlCollSub.unsubscribe()
currentUserSub.unsubscribe()
initCollectionsSync()
}
}
)
}
export const def: CollectionsPlatformDef = {
initCollectionsSync,
}

View File

@@ -1,186 +0,0 @@
import { Environment } from "@hoppscotch/data"
import {
collection,
doc,
getFirestore,
onSnapshot,
setDoc,
} from "firebase/firestore"
import { def as platformAuth } from "./firebase/auth"
import {
environments$,
globalEnv$,
replaceEnvironments,
setGlobalEnvVariables,
} from "@hoppscotch/common/newstore/environments"
import {
getSettingSubject,
settingsStore,
} from "@hoppscotch/common/newstore/settings"
import { EnvironmentsPlatformDef } from "@hoppscotch/common/platform/environments"
/**
* Used locally to prevent infinite loop when environment sync update
* is applied to the store which then fires the store sync listener.
* When you want to update environments and not want to fire the update listener,
* set this to true and then set it back to false once it is done
*/
let loadedEnvironments = false
/**
* Used locally to prevent infinite loop when global env sync update
* is applied to the store which then fires the store sync listener.
* When you want to update global env and not want to fire the update listener,
* set this to true and then set it back to false once it is done
*/
let loadedGlobals = true
async function writeEnvironments(environment: Environment[]) {
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("Cannot write environments when signed out")
const ev = {
updatedOn: new Date(),
author: currentUser.uid,
author_name: currentUser.displayName,
author_image: currentUser.photoURL,
environment,
}
try {
await setDoc(
doc(getFirestore(), "users", currentUser.uid, "environments", "sync"),
ev
)
} catch (e) {
console.error("error updating", ev, e)
throw e
}
}
async function writeGlobalEnvironment(variables: Environment["variables"]) {
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("Cannot write global environment when signed out")
const ev = {
updatedOn: new Date(),
author: currentUser.uid,
author_name: currentUser.displayName,
author_image: currentUser.photoURL,
variables,
}
try {
await setDoc(
doc(getFirestore(), "users", currentUser.uid, "globalEnv", "sync"),
ev
)
} catch (e) {
console.error("error updating", ev, e)
throw e
}
}
export function initEnvironmentsSync() {
const currentUser$ = platformAuth.getCurrentUserStream()
const envListenSub = environments$.subscribe((envs) => {
const currentUser = platformAuth.getCurrentUser()
if (
currentUser &&
settingsStore.value.syncEnvironments &&
loadedEnvironments
) {
writeEnvironments(envs)
}
})
const globalListenSub = globalEnv$.subscribe((vars) => {
const currentUser = platformAuth.getCurrentUser()
if (currentUser && settingsStore.value.syncEnvironments && loadedGlobals) {
writeGlobalEnvironment(vars)
}
})
let envSnapshotStop: (() => void) | null = null
let globalsSnapshotStop: (() => void) | null = null
const currentUserSub = currentUser$.subscribe((user) => {
if (!user) {
// User logged out, clean up snapshot listener
if (envSnapshotStop) {
envSnapshotStop()
envSnapshotStop = null
}
if (globalsSnapshotStop) {
globalsSnapshotStop()
globalsSnapshotStop = null
}
} else if (user) {
envSnapshotStop = onSnapshot(
collection(getFirestore(), "users", user.uid, "environments"),
(environmentsRef) => {
const environments: any[] = []
environmentsRef.forEach((doc) => {
const environment = doc.data()
environment.id = doc.id
environments.push(environment)
})
loadedEnvironments = false
if (environments.length > 0 && settingsStore.value.syncEnvironments) {
replaceEnvironments(environments[0].environment)
}
loadedEnvironments = true
}
)
globalsSnapshotStop = onSnapshot(
collection(getFirestore(), "users", user.uid, "globalEnv"),
(globalsRef) => {
if (globalsRef.docs.length === 0) {
loadedGlobals = true
return
}
const doc = globalsRef.docs[0].data()
loadedGlobals = false
if (settingsStore.value.syncEnvironments)
setGlobalEnvVariables(doc.variables)
loadedGlobals = true
}
)
}
})
let oldSyncStatus = settingsStore.value.syncEnvironments
const syncStop = getSettingSubject("syncEnvironments").subscribe(
(newStatus) => {
if (oldSyncStatus === true && newStatus === false) {
envSnapshotStop?.()
globalsSnapshotStop?.()
oldSyncStatus = newStatus
} else if (oldSyncStatus === false && newStatus === true) {
syncStop.unsubscribe()
envListenSub.unsubscribe()
globalListenSub.unsubscribe()
currentUserSub.unsubscribe()
initEnvironmentsSync()
}
}
)
}
export const def: EnvironmentsPlatformDef = {
initEnvironmentsSync,
}

View File

@@ -1,436 +0,0 @@
import {
AuthEvent,
AuthPlatformDef,
HoppUser,
} from "@hoppscotch/common/platform/auth"
import {
Subscription,
BehaviorSubject,
Subject,
filter,
map,
combineLatest,
} from "rxjs"
import {
setDoc,
onSnapshot,
updateDoc,
doc,
getFirestore,
} from "firebase/firestore"
import {
AuthError,
AuthCredential,
User as FBUser,
sendSignInLinkToEmail,
linkWithCredential,
getAuth,
ActionCodeSettings,
isSignInWithEmailLink as isSignInWithEmailLinkFB,
signInWithEmailLink as signInWithEmailLinkFB,
sendEmailVerification,
signInWithPopup,
GoogleAuthProvider,
GithubAuthProvider,
OAuthProvider,
fetchSignInMethodsForEmail,
updateEmail,
updateProfile,
reauthenticateWithCredential,
onAuthStateChanged,
onIdTokenChanged,
signOut,
} from "firebase/auth"
import {
getLocalConfig,
removeLocalConfig,
setLocalConfig,
} from "@hoppscotch/common/newstore/localpersistence"
export const currentUserFB$ = new BehaviorSubject<FBUser | null>(null)
export const authEvents$ = new Subject<AuthEvent>()
export const probableUser$ = new BehaviorSubject<HoppUser | null>(null)
const authIdToken$ = new BehaviorSubject<string | null>(null)
async function signInWithEmailLink(email: string, url: string) {
return await signInWithEmailLinkFB(getAuth(), email, url)
}
function fbUserToHoppUser(user: FBUser): HoppUser {
return {
uid: user.uid,
displayName: user.displayName,
email: user.email,
photoURL: user.photoURL,
emailVerified: user.emailVerified,
}
}
const currentUser$ = new BehaviorSubject<HoppUser | null>(null)
const EMAIL_ACTION_CODE_SETTINGS: ActionCodeSettings = {
url: `${import.meta.env.VITE_BASE_URL}/enter`,
handleCodeInApp: true,
}
async function signInUserWithGithubFB() {
return await signInWithPopup(
getAuth(),
new GithubAuthProvider().addScope("gist")
)
}
async function signInUserWithGoogleFB() {
return await signInWithPopup(getAuth(), new GoogleAuthProvider())
}
async function signInUserWithMicrosoftFB() {
return await signInWithPopup(getAuth(), new OAuthProvider("microsoft.com"))
}
/**
* Reauthenticate the user with the given credential
*/
async function reauthenticateUser() {
if (!currentUserFB$.value || !currentUser$.value)
throw new Error("No user has logged in")
const currentAuthMethod = currentUser$.value.provider
let credential
if (currentAuthMethod === "google.com") {
// const result = await signInUserWithGithubFB()
const result = await signInUserWithGoogleFB()
credential = GithubAuthProvider.credentialFromResult(result)
} else if (currentAuthMethod === "github.com") {
// const result = await signInUserWithGoogleFB()
const result = await signInUserWithGithubFB()
credential = GoogleAuthProvider.credentialFromResult(result)
} else if (currentAuthMethod === "microsoft.com") {
const result = await signInUserWithMicrosoftFB()
credential = OAuthProvider.credentialFromResult(result)
} else if (currentAuthMethod === "password") {
const email = prompt(
"Reauthenticate your account using your current email:"
)
await def
.signInWithEmail(email as string)
.then(() =>
alert(
`Check your inbox - we sent an email to ${email}. It contains a magic link that will reauthenticate your account.`
)
)
.catch((e) => {
alert(`Error: ${e.message}`)
console.error(e)
})
return
}
try {
await reauthenticateWithCredential(
currentUserFB$.value,
credential as AuthCredential
)
} catch (e) {
console.error("error updating", e)
throw e
}
}
/**
* Links account with another account given in a auth/account-exists-with-different-credential error
*
* @param error - Error caught after trying to login
*
* @returns Promise of UserCredential
*/
async function linkWithFBCredentialFromAuthError(error: unknown) {
// credential is not null since this function is called after an auth/account-exists-with-different-credential error, ie credentials actually exist
const credentials = OAuthProvider.credentialFromError(error as AuthError)!
const otherLinkedProviders = (
await getSignInMethodsForEmail((error as AuthError).customData.email!)
).filter((providerId) => credentials.providerId !== providerId)
let user: FBUser | null = null
if (otherLinkedProviders.indexOf("google.com") >= -1) {
user = (await signInUserWithGoogleFB()).user
} else if (otherLinkedProviders.indexOf("github.com") >= -1) {
user = (await signInUserWithGithubFB()).user
} else if (otherLinkedProviders.indexOf("microsoft.com") >= -1) {
user = (await signInUserWithMicrosoftFB()).user
}
// user is not null since going through each provider will return a user
return await linkWithCredential(user!, credentials)
}
async function setProviderInfo(id: string, token: string) {
if (!currentUser$.value) throw new Error("No user has logged in")
const us = {
updatedOn: new Date(),
provider: id,
accessToken: token,
}
try {
await updateDoc(doc(getFirestore(), "users", currentUser$.value.uid), us)
} catch (e) {
console.error("error updating provider info", e)
throw e
}
}
async function getSignInMethodsForEmail(email: string) {
return await fetchSignInMethodsForEmail(getAuth(), email)
}
export const def: AuthPlatformDef = {
getCurrentUserStream: () => currentUser$,
getAuthEventsStream: () => authEvents$,
getProbableUserStream: () => probableUser$,
getCurrentUser: () => currentUser$.value,
getProbableUser: () => probableUser$.value,
getBackendHeaders() {
return {
authorization: `Bearer ${authIdToken$.value}`,
}
},
willBackendHaveAuthError() {
return !authIdToken$.value
},
onBackendGQLClientShouldReconnect(func) {
authIdToken$.subscribe(() => {
func()
})
},
getDevOptsBackendIDToken() {
return authIdToken$.value
},
performAuthInit() {
// todo: implement
const auth = getAuth()
const firestore = getFirestore()
combineLatest([currentUserFB$, authIdToken$])
.pipe(
map(([user, token]) => {
// If there is no auth token, we will just consider as the auth as not complete
if (token === null) return null
if (user !== null) return fbUserToHoppUser(user)
return null
})
)
.subscribe((x) => {
currentUser$.next(x)
})
let extraSnapshotStop: (() => void) | null = null
probableUser$.next(JSON.parse(getLocalConfig("login_state") ?? "null"))
onAuthStateChanged(auth, (user) => {
const wasLoggedIn = currentUser$.value !== null
if (user) {
probableUser$.next(user)
} else {
probableUser$.next(null)
removeLocalConfig("login_state")
}
if (!user && extraSnapshotStop) {
extraSnapshotStop()
extraSnapshotStop = null
} else if (user) {
// Merge all the user info from all the authenticated providers
user.providerData.forEach((profile) => {
if (!profile) return
const us = {
updatedOn: new Date(),
provider: profile.providerId,
name: profile.displayName,
email: profile.email,
photoUrl: profile.photoURL,
uid: profile.uid,
}
setDoc(doc(firestore, "users", user.uid), us, { merge: true }).catch(
(e) => console.error("error updating", us, e)
)
})
extraSnapshotStop = onSnapshot(
doc(firestore, "users", user.uid),
(doc) => {
const data = doc.data()
const userUpdate: HoppUser = fbUserToHoppUser(user)
if (data) {
// Write extra provider data
userUpdate.provider = data.provider
userUpdate.accessToken = data.accessToken
}
currentUser$.next(userUpdate)
}
)
}
currentUserFB$.next(user)
currentUser$.next(user === null ? null : fbUserToHoppUser(user))
// User wasn't found before, but now is there (login happened)
if (!wasLoggedIn && user) {
authEvents$.next({
event: "login",
user: currentUser$.value!,
})
} else if (wasLoggedIn && !user) {
// User was found before, but now is not there (logout happened)
authEvents$.next({
event: "logout",
})
}
})
onIdTokenChanged(auth, async (user) => {
if (user) {
authIdToken$.next(await user.getIdToken())
setLocalConfig("login_state", JSON.stringify(user))
} else {
authIdToken$.next(null)
}
})
},
waitProbableLoginToConfirm() {
return new Promise<void>((resolve, reject) => {
if (authIdToken$.value) resolve()
if (!probableUser$.value) reject(new Error("no_probable_user"))
let sub: Subscription | null = null
sub = authIdToken$.pipe(filter((token) => !!token)).subscribe(() => {
sub?.unsubscribe()
resolve()
})
})
},
async signInWithEmail(email: string) {
return await sendSignInLinkToEmail(
getAuth(),
email,
EMAIL_ACTION_CODE_SETTINGS
)
},
isSignInWithEmailLink(url: string) {
return isSignInWithEmailLinkFB(getAuth(), url)
},
async verifyEmailAddress() {
if (!currentUserFB$.value) throw new Error("No user has logged in")
try {
await sendEmailVerification(currentUserFB$.value)
} catch (e) {
console.error("error verifying email address", e)
throw e
}
},
async signInUserWithGoogle() {
await signInUserWithGoogleFB()
},
async signInUserWithGithub() {
try {
const cred = await signInUserWithGithubFB()
const oAuthCred = GithubAuthProvider.credentialFromResult(cred)!
const token = oAuthCred.accessToken
await setProviderInfo(cred.providerId!, token!)
return {
type: "success",
user: fbUserToHoppUser(cred.user),
}
} catch (e) {
console.error("error while logging in with github", e)
if ((e as any).code === "auth/account-exists-with-different-credential") {
return {
type: "account-exists-with-different-cred",
link: async () => {
await linkWithFBCredentialFromAuthError(e)
},
}
} else {
return {
type: "error",
err: e,
}
}
}
},
async signInUserWithMicrosoft() {
await signInUserWithMicrosoftFB()
},
async signInWithEmailLink(email: string, url: string) {
await signInWithEmailLinkFB(getAuth(), email, url)
},
async setEmailAddress(email: string) {
if (!currentUserFB$.value) throw new Error("No user has logged in")
try {
await updateEmail(currentUserFB$.value, email)
} catch (e) {
await reauthenticateUser()
console.log("error setting email address", e)
throw e
}
},
async setDisplayName(name: string) {
if (!currentUserFB$.value) throw new Error("No user has logged in")
const us = {
displayName: name,
}
try {
await updateProfile(currentUserFB$.value, us)
} catch (e) {
console.error("error updating display name", e)
throw e
}
},
async signOutUser() {
if (!currentUser$.value) throw new Error("No user has logged in")
await signOut(getAuth())
},
async processMagicLink() {
if (this.isSignInWithEmailLink(window.location.href)) {
let email = getLocalConfig("emailForSignIn")
if (!email) {
email = window.prompt(
"Please provide your email for confirmation"
) as string
}
await signInWithEmailLink(email, window.location.href)
removeLocalConfig("emailForSignIn")
window.location.href = "/"
}
},
}

View File

@@ -1,26 +0,0 @@
import { initializeApp } from "firebase/app"
const firebaseConfig = {
apiKey: import.meta.env.VITE_API_KEY,
authDomain: import.meta.env.VITE_AUTH_DOMAIN,
databaseURL: import.meta.env.VITE_DATABASE_URL,
projectId: import.meta.env.VITE_PROJECT_ID,
storageBucket: import.meta.env.VITE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_APP_ID,
measurementId: import.meta.env.VITE_MEASUREMENT_ID,
}
let initialized = false
export function initializeFirebase() {
if (!initialized) {
try {
initializeApp(firebaseConfig)
initialized = true
} catch (e) {
// initializeApp throws exception if we reinitialize
initialized = true
}
}
}

View File

@@ -1,276 +0,0 @@
import {
addDoc,
collection,
deleteDoc,
doc,
getDocs,
getFirestore,
limit,
onSnapshot,
orderBy,
query,
updateDoc,
} from "firebase/firestore"
import { FormDataKeyValue } from "@hoppscotch/data"
import { def as platformAuth } from "./firebase/auth"
import {
getSettingSubject,
settingsStore,
} from "@hoppscotch/common/newstore/settings"
import {
GQLHistoryEntry,
graphqlHistoryStore,
HISTORY_LIMIT,
RESTHistoryEntry,
restHistoryStore,
setGraphqlHistoryEntries,
setRESTHistoryEntries,
translateToNewGQLHistory,
translateToNewRESTHistory,
} from "@hoppscotch/common/newstore/history"
import { HistoryPlatformDef } from "@hoppscotch/common/platform/history"
type HistoryFBCollections = "history" | "graphqlHistory"
/**
* Whether the history are loaded. If this is set to true
* Updates to the history store are written into firebase.
*
* If you have want to update the store and not fire the store update
* subscription, set this variable to false, do the update and then
* set it to true
*/
let loadedRESTHistory = false
/**
* Whether the history are loaded. If this is set to true
* Updates to the history store are written into firebase.
*
* If you have want to update the store and not fire the store update
* subscription, set this variable to false, do the update and then
* set it to true
*/
let loadedGraphqlHistory = false
const purgeFormDataFromRequest = (req: RESTHistoryEntry): RESTHistoryEntry => {
if (req.request.body.contentType !== "multipart/form-data") return req
req.request.body.body = req.request.body.body.map<FormDataKeyValue>(
(formData) => {
if (!formData.isFile) return formData
return {
active: formData.active,
isFile: false, // Something we can do to keep the status ?
key: formData.key,
value: "",
}
}
)
return req
}
async function writeHistory(
entry: RESTHistoryEntry | GQLHistoryEntry,
col: HistoryFBCollections
) {
const processedEntry =
col === "history"
? purgeFormDataFromRequest(entry as RESTHistoryEntry)
: entry
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("User not logged in to sync history")
const hs = {
...processedEntry,
updatedOn: new Date(),
}
try {
await addDoc(collection(getFirestore(), "users", currentUser.uid, col), hs)
} catch (e) {
console.error("error writing to history", hs, e)
throw e
}
}
async function deleteHistory(
entry: (RESTHistoryEntry | GQLHistoryEntry) & { id: string },
col: HistoryFBCollections
) {
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("User not logged in to delete history")
try {
await deleteDoc(
doc(getFirestore(), "users", currentUser.uid, col, entry.id)
)
} catch (e) {
console.error("error deleting history", entry, e)
throw e
}
}
async function clearHistory(col: HistoryFBCollections) {
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("User not logged in to clear history")
const { docs } = await getDocs(
collection(getFirestore(), "users", currentUser.uid, col)
)
await Promise.all(docs.map((e) => deleteHistory(e as any, col)))
}
async function toggleStar(
entry: (RESTHistoryEntry | GQLHistoryEntry) & { id: string },
col: HistoryFBCollections
) {
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null) throw new Error("User not logged in to toggle star")
try {
await updateDoc(
doc(getFirestore(), "users", currentUser.uid, col, entry.id),
{ star: !entry.star }
)
} catch (e) {
console.error("error toggling star", entry, e)
throw e
}
}
export function initHistorySync() {
const currentUser$ = platformAuth.getCurrentUserStream()
const restHistorySub = restHistoryStore.dispatches$.subscribe((dispatch) => {
const currentUser = platformAuth.getCurrentUser()
if (loadedRESTHistory && currentUser && settingsStore.value.syncHistory) {
if (dispatch.dispatcher === "addEntry") {
writeHistory(dispatch.payload.entry, "history")
} else if (dispatch.dispatcher === "deleteEntry") {
deleteHistory(dispatch.payload.entry, "history")
} else if (dispatch.dispatcher === "clearHistory") {
clearHistory("history")
} else if (dispatch.dispatcher === "toggleStar") {
toggleStar(dispatch.payload.entry, "history")
}
}
})
const gqlHistorySub = graphqlHistoryStore.dispatches$.subscribe(
(dispatch) => {
const currentUser = platformAuth.getCurrentUser()
if (
loadedGraphqlHistory &&
currentUser &&
settingsStore.value.syncHistory
) {
if (dispatch.dispatcher === "addEntry") {
writeHistory(dispatch.payload.entry, "graphqlHistory")
} else if (dispatch.dispatcher === "deleteEntry") {
deleteHistory(dispatch.payload.entry, "graphqlHistory")
} else if (dispatch.dispatcher === "clearHistory") {
clearHistory("graphqlHistory")
} else if (dispatch.dispatcher === "toggleStar") {
toggleStar(dispatch.payload.entry, "graphqlHistory")
}
}
}
)
let restSnapshotStop: (() => void) | null = null
let graphqlSnapshotStop: (() => void) | null = null
const currentUserSub = currentUser$.subscribe((user) => {
if (!user) {
// Clear the snapshot listeners when the user logs out
if (restSnapshotStop) {
restSnapshotStop()
restSnapshotStop = null
}
if (graphqlSnapshotStop) {
graphqlSnapshotStop()
graphqlSnapshotStop = null
}
} else {
restSnapshotStop = onSnapshot(
query(
collection(getFirestore(), "users", user.uid, "history"),
orderBy("updatedOn", "desc"),
limit(HISTORY_LIMIT)
),
(historyRef) => {
const history: RESTHistoryEntry[] = []
historyRef.forEach((doc) => {
const entry = doc.data()
entry.id = doc.id
entry.updatedOn = doc.data().updatedOn.toDate()
history.push(translateToNewRESTHistory(entry))
})
loadedRESTHistory = false
setRESTHistoryEntries(history)
loadedRESTHistory = true
}
)
graphqlSnapshotStop = onSnapshot(
query(
collection(getFirestore(), "users", user.uid, "graphqlHistory"),
orderBy("updatedOn", "desc"),
limit(HISTORY_LIMIT)
),
(historyRef) => {
const history: GQLHistoryEntry[] = []
historyRef.forEach((doc) => {
const entry = doc.data()
entry.id = doc.id
entry.updatedOn = doc.data().updatedOn.toDate()
history.push(translateToNewGQLHistory(entry))
})
loadedGraphqlHistory = false
setGraphqlHistoryEntries(history)
loadedGraphqlHistory = true
}
)
}
})
let oldSyncStatus = settingsStore.value.syncHistory
const syncStop = getSettingSubject("syncHistory").subscribe((newStatus) => {
if (oldSyncStatus === true && newStatus === false) {
restSnapshotStop?.()
graphqlSnapshotStop?.()
oldSyncStatus = newStatus
} else if (oldSyncStatus === false && newStatus === true) {
syncStop.unsubscribe()
restHistorySub.unsubscribe()
gqlHistorySub.unsubscribe()
currentUserSub.unsubscribe()
initHistorySync()
}
})
}
export const def: HistoryPlatformDef = {
initHistorySync,
}

View File

@@ -1,26 +0,0 @@
import { createHoppApp } from "@hoppscotch/common"
import { initializeFirebase } from "./firebase/init"
import { def as authDef } from "./firebase/auth"
import { def as envDef } from "./environments"
import { def as collectionsDef } from "./collections"
import { def as settingsDef } from "./settings"
import { def as historyDef } from "./history"
import { def as tabStateDef } from "./tab"
import { def as analyticsDef } from "./analytics"
initializeFirebase()
createHoppApp("#app", {
auth: authDef,
analytics: analyticsDef,
sync: {
environments: envDef,
collections: collectionsDef,
settings: settingsDef,
history: historyDef,
tabState: tabStateDef,
},
platformFeatureFlags: {
exportAsGIST: true,
},
})

View File

@@ -1,108 +0,0 @@
import {
collection,
doc,
getFirestore,
onSnapshot,
setDoc,
} from "firebase/firestore"
import { def as platformAuth } from "./firebase/auth"
import {
applySetting,
settingsStore,
SettingsDef,
} from "@hoppscotch/common/newstore/settings"
import { SettingsPlatformDef } from "@hoppscotch/common/platform/settings"
/**
* Used locally to prevent infinite loop when settings sync update
* is applied to the store which then fires the store sync listener.
* When you want to update settings and not want to fire the update listener,
* set this to true and then set it back to false once it is done
*/
let loadedSettings = false
/**
* Write Transform
*/
async function writeSettings(setting: string, value: any) {
const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("Cannot write setting, user not signed in")
const st = {
updatedOn: new Date(),
author: currentUser.uid,
author_name: currentUser.displayName,
author_image: currentUser.photoURL,
name: setting,
value,
}
try {
await setDoc(
doc(getFirestore(), "users", currentUser.uid, "settings", setting),
st
)
} catch (e) {
console.error("error updating", st, e)
throw e
}
}
export function initSettingsSync() {
const currentUser$ = platformAuth.getCurrentUserStream()
settingsStore.dispatches$.subscribe((dispatch) => {
const currentUser = platformAuth.getCurrentUser()
if (currentUser && loadedSettings) {
if (dispatch.dispatcher === "bulkApplySettings") {
Object.keys(dispatch.payload).forEach((key) => {
writeSettings(key, dispatch.payload[key])
})
} else {
writeSettings(
dispatch.payload.settingKey,
settingsStore.value[dispatch.payload.settingKey as keyof SettingsDef]
)
}
}
})
let snapshotStop: (() => void) | null = null
// Subscribe and unsubscribe event listeners
currentUser$.subscribe((user) => {
if (!user && snapshotStop) {
// User logged out
snapshotStop()
snapshotStop = null
} else if (user) {
snapshotStop = onSnapshot(
collection(getFirestore(), "users", user.uid, "settings"),
(settingsRef) => {
const settings: any[] = []
settingsRef.forEach((doc) => {
const setting = doc.data()
setting.id = doc.id
settings.push(setting)
})
loadedSettings = false
settings.forEach((e) => {
if (e && e.name && e.value != null) {
applySetting(e.name, e.value)
}
})
loadedSettings = true
}
)
}
})
}
export const def: SettingsPlatformDef = {
initSettingsSync,
}

View File

@@ -1,48 +0,0 @@
import { PersistableRESTTabState } from "@hoppscotch/common/helpers/rest/tab"
import { HoppUser } from "@hoppscotch/common/platform/auth"
import { TabStatePlatformDef } from "@hoppscotch/common/platform/tab"
import { doc, getDoc, getFirestore, setDoc } from "firebase/firestore"
import { def as platformAuth } from "./firebase/auth"
/**
* Writes tab state to a user's firestore sync
*
* @param persistableTabState The tab state to write to the request sync
*/
function writeCurrentTabState(
user: HoppUser,
persistableTabState: PersistableRESTTabState
) {
// Remove FormData entries because those can't be stored on Firestore ?
return setDoc(
doc(getFirestore(), "users", user.uid, "requests", "tab-state"),
persistableTabState
)
}
/**
* Loads the synced tab state from the firestore sync
*
* @returns Fetched tab state object if exists else null
*/
async function loadTabStateFromSync(): Promise<PersistableRESTTabState | null> {
const currentUser = platformAuth.getCurrentUser()
if (!currentUser)
throw new Error("Cannot load request from sync without login")
const fbDoc = await getDoc(
doc(getFirestore(), "users", currentUser.uid, "requests", "tab-state")
)
const data = fbDoc.data()
if (!data) return null
else return data as PersistableRESTTabState
}
export const def: TabStatePlatformDef = {
loadTabStateFromSync,
writeCurrentTabState,
}

View File

@@ -1,7 +0,0 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

View File

@@ -1,23 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true,
"paths": {
"@hoppscotch/common": [ "../hoppscotch-common/src/index.ts" ],
"@hoppscotch/common/*": [ "../hoppscotch-common/src/*" ]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -1,9 +0,0 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "meta.ts"]
}

View File

@@ -1,195 +0,0 @@
import { defineConfig, loadEnv, normalizePath } from "vite"
import { APP_INFO, META_TAGS } from "./meta"
import { viteStaticCopy as StaticCopy } from "vite-plugin-static-copy"
import generateSitemap from "vite-plugin-pages-sitemap"
import HtmlConfig from "vite-plugin-html-config"
import Vue from "@vitejs/plugin-vue"
import VueI18n from "@intlify/vite-plugin-vue-i18n"
import Components from "unplugin-vue-components/vite"
import Icons from "unplugin-icons/vite"
import Inspect from "vite-plugin-inspect"
import WindiCSS from "vite-plugin-windicss"
import { VitePWA } from "vite-plugin-pwa"
import Pages from "vite-plugin-pages"
import Layouts from "vite-plugin-vue-layouts"
import IconResolver from "unplugin-icons/resolver"
import { FileSystemIconLoader } from "unplugin-icons/loaders"
import * as path from "path"
import { VitePluginFonts } from "vite-plugin-fonts"
import legacy from "@vitejs/plugin-legacy"
const ENV = loadEnv("development", path.resolve(__dirname, "../../"))
export default defineConfig({
envDir: path.resolve(__dirname, "../../"),
// TODO: Migrate @hoppscotch/data to full ESM
define: {
// For 'util' polyfill required by dep of '@apidevtools/swagger-parser'
"process.env": {},
},
server: {
port: 3000,
},
preview: {
port: 3000,
},
publicDir: path.resolve(__dirname, "../hoppscotch-common/public"),
build: {
sourcemap: true,
emptyOutDir: true,
},
resolve: {
alias: {
// TODO: Maybe leave ~ only for individual apps and not use on common
"~": path.resolve(__dirname, "../hoppscotch-common/src"),
"@hoppscotch/common": "@hoppscotch/common/src",
"@composables": path.resolve(
__dirname,
"../hoppscotch-common/src/composables"
),
"@modules": path.resolve(__dirname, "../hoppscotch-common/src/modules"),
"@components": path.resolve(
__dirname,
"../hoppscotch-common/src/components"
),
"@helpers": path.resolve(__dirname, "../hoppscotch-common/src/helpers"),
"@functional": path.resolve(
__dirname,
"../hoppscotch-common/src/helpers/functional"
),
"@workers": path.resolve(__dirname, "../hoppscotch-common/src/workers"),
stream: "stream-browserify",
util: "util",
},
dedupe: ["vue"],
},
plugins: [
Inspect(), // go to url -> /__inspect
HtmlConfig({
metas: META_TAGS(ENV),
}),
Vue(),
Pages({
routeStyle: "nuxt",
dirs: "../hoppscotch-common/src/pages",
importMode: "async",
onRoutesGenerated(routes) {
// HACK: See: https://github.com/jbaubree/vite-plugin-pages-sitemap/issues/173
return ((generateSitemap as any).default as typeof generateSitemap)({
routes,
nuxtStyle: true,
allowRobots: true,
dest: ".sitemap-gen",
hostname: ENV.VITE_BASE_URL,
})
},
}),
StaticCopy({
targets: [
{
src: normalizePath(path.resolve(__dirname, "./.sitemap-gen/*")),
dest: normalizePath(path.resolve(__dirname, "./dist")),
},
],
}),
Layouts({
layoutsDirs: "../hoppscotch-common/src/layouts",
defaultLayout: "default",
}),
VueI18n({
runtimeOnly: false,
compositionOnly: true,
include: [path.resolve(__dirname, "locales")],
}),
WindiCSS({
root: path.resolve(__dirname, "../hoppscotch-common"),
}),
Components({
dts: "../hoppscotch-common/src/components.d.ts",
dirs: ["../hoppscotch-common/src/components"],
directoryAsNamespace: true,
resolvers: [
IconResolver({
prefix: "icon",
customCollections: ["hopp", "auth", "brands"],
}),
(compName: string) => {
if (compName.startsWith("Hopp"))
return { name: compName, from: "@hoppscotch/ui" }
else return undefined
},
],
types: [
{
from: "vue-tippy",
names: ["Tippy"],
},
],
}),
Icons({
compiler: "vue3",
customCollections: {
hopp: FileSystemIconLoader("../hoppscotch-common/assets/icons"),
auth: FileSystemIconLoader("../hoppscotch-common/assets/icons/auth"),
brands: FileSystemIconLoader(
"../hoppscotch-common/assets/icons/brands"
),
},
}),
VitePWA({
manifest: {
name: APP_INFO.name,
short_name: APP_INFO.name,
description: APP_INFO.shortDescription,
start_url: "/?source=pwa",
background_color: APP_INFO.app.background,
theme_color: APP_INFO.app.background,
icons: [
{
src: "/icon.png",
sizes: "512x512",
type: "image/png",
purpose: "any maskable",
},
{
src: "/logo.svg",
sizes: "48x48 72x72 96x96 128x128 256x256 512x512",
type: "image/svg+xml",
purpose: "any maskable",
},
],
},
registerType: "prompt",
workbox: {
cleanupOutdatedCaches: true,
maximumFileSizeToCacheInBytes: 4194304,
navigateFallbackDenylist: [
/robots.txt/,
/sitemap.xml/,
/discord/,
/telegram/,
/beta/,
/careers/,
/newsletter/,
/twitter/,
/github/,
/announcements/,
],
},
}),
VitePluginFonts({
google: {
families: [
"Inter:wght@400;500;600;700;800",
"Roboto+Mono:wght@400;500",
"Material+Icons",
],
},
}),
legacy({
modernPolyfills: ["es.string.replace-all"],
renderLegacyChunks: false,
}),
],
})

412
pnpm-lock.yaml generated
View File

@@ -1310,121 +1310,6 @@ importers:
specifier: ^3.5.6
version: 3.5.6
packages/hoppscotch-web:
dependencies:
'@hoppscotch/common':
specifier: workspace:^
version: link:../hoppscotch-common
'@hoppscotch/data':
specifier: workspace:^
version: link:../hoppscotch-data
'@hoppscotch/ui':
specifier: workspace:^
version: link:../hoppscotch-ui
buffer:
specifier: ^6.0.3
version: 6.0.3
firebase:
specifier: ^9.8.4
version: 9.8.4
process:
specifier: ^0.11.10
version: 0.11.10
rxjs:
specifier: ^7.5.5
version: 7.5.5
stream-browserify:
specifier: ^3.0.0
version: 3.0.0
util:
specifier: ^0.12.4
version: 0.12.4
vue:
specifier: ^3.2.41
version: 3.2.45
workbox-window:
specifier: ^6.5.4
version: 6.5.4
devDependencies:
'@intlify/vite-plugin-vue-i18n':
specifier: ^6.0.1
version: 6.0.1(vite@3.1.4)(vue-i18n@9.2.2)
'@rushstack/eslint-patch':
specifier: ^1.1.4
version: 1.1.4
'@typescript-eslint/eslint-plugin':
specifier: ^5.19.0
version: 5.30.6(@typescript-eslint/parser@5.30.6)(eslint@8.28.0)(typescript@4.7.4)
'@typescript-eslint/parser':
specifier: ^5.19.0
version: 5.30.6(eslint@8.28.0)(typescript@4.7.4)
'@vitejs/plugin-legacy':
specifier: ^2.3.0
version: 2.3.0(terser@5.14.1)(vite@3.2.4)
'@vitejs/plugin-vue':
specifier: ^3.2.0
version: 3.2.0(vite@3.2.4)(vue@3.2.45)
'@vue/eslint-config-typescript':
specifier: ^11.0.1
version: 11.0.1(eslint-plugin-vue@9.5.1)(eslint@8.28.0)(typescript@4.7.4)
cross-env:
specifier: ^7.0.3
version: 7.0.3
eslint:
specifier: ^8.28.0
version: 8.28.0
eslint-plugin-prettier:
specifier: ^4.2.1
version: 4.2.1(eslint-config-prettier@8.6.0)(eslint@8.19.0)(prettier@2.8.4)
eslint-plugin-vue:
specifier: ^9.5.1
version: 9.5.1(eslint@8.28.0)
typescript:
specifier: ^4.6.4
version: 4.7.4
unplugin-icons:
specifier: ^0.14.9
version: 0.14.9(@vue/compiler-sfc@3.2.39)(esbuild@0.15.15)(rollup@2.79.1)(vite@3.1.4)
unplugin-vue-components:
specifier: ^0.21.0
version: 0.21.0(esbuild@0.15.15)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45)(webpack@5.74.0)
vite:
specifier: ^3.2.3
version: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.14.1)
vite-plugin-fonts:
specifier: ^0.6.0
version: 0.6.0(vite@3.2.4)
vite-plugin-html-config:
specifier: ^1.0.10
version: 1.0.10(vite@3.2.4)
vite-plugin-inspect:
specifier: ^0.7.4
version: 0.7.4(vite@3.2.4)
vite-plugin-pages:
specifier: ^0.26.0
version: 0.26.0(@vue/compiler-sfc@3.2.45)(vite@3.2.4)
vite-plugin-pages-sitemap:
specifier: ^1.4.0
version: 1.4.0
vite-plugin-pwa:
specifier: ^0.13.1
version: 0.13.1(vite@3.2.4)(workbox-build@6.5.4)(workbox-window@6.5.4)
vite-plugin-static-copy:
specifier: ^0.12.0
version: 0.12.0(vite@3.2.4)
vite-plugin-vue-layouts:
specifier: ^0.7.0
version: 0.7.0(vite@3.2.4)(vue-router@4.1.0)(vue@3.2.45)
vite-plugin-windicss:
specifier: ^1.8.8
version: 1.8.8(vite@3.2.4)
vue-tsc:
specifier: ^1.0.9
version: 1.0.9(typescript@4.7.4)
windicss:
specifier: ^3.5.6
version: 3.5.6
packages:
/@ampproject/remapping@2.2.0:
@@ -7687,33 +7572,6 @@ packages:
- supports-color
dev: true
/@typescript-eslint/eslint-plugin@5.30.6(@typescript-eslint/parser@5.30.6)(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
'@typescript-eslint/parser': ^5.0.0
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.30.6(eslint@8.28.0)(typescript@4.7.4)
'@typescript-eslint/scope-manager': 5.30.6
'@typescript-eslint/type-utils': 5.30.6(eslint@8.28.0)(typescript@4.7.4)
'@typescript-eslint/utils': 5.30.6(eslint@8.28.0)(typescript@4.7.4)
debug: 4.3.4(supports-color@9.2.2)
eslint: 8.28.0
functional-red-black-tree: 1.0.1
ignore: 5.2.0
regexpp: 3.2.0
semver: 7.3.7
tsutils: 3.21.0(typescript@4.7.4)
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/eslint-plugin@5.45.0(@typescript-eslint/parser@5.45.0)(eslint@8.24.0)(typescript@4.7.4):
resolution: {integrity: sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7741,33 +7599,6 @@ packages:
- supports-color
dev: true
/@typescript-eslint/eslint-plugin@5.45.0(@typescript-eslint/parser@5.45.0)(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
'@typescript-eslint/parser': ^5.0.0
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.45.0(eslint@8.28.0)(typescript@4.7.4)
'@typescript-eslint/scope-manager': 5.45.0
'@typescript-eslint/type-utils': 5.45.0(eslint@8.28.0)(typescript@4.7.4)
'@typescript-eslint/utils': 5.45.0(eslint@8.28.0)(typescript@4.7.4)
debug: 4.3.4(supports-color@9.2.2)
eslint: 8.28.0
ignore: 5.2.0
natural-compare-lite: 1.4.0
regexpp: 3.2.0
semver: 7.3.8
tsutils: 3.21.0(typescript@4.7.4)
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/eslint-plugin@5.45.0(@typescript-eslint/parser@5.45.0)(eslint@8.29.0)(typescript@4.9.3):
resolution: {integrity: sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7835,26 +7666,6 @@ packages:
- supports-color
dev: true
/@typescript-eslint/parser@5.30.6(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 5.30.6
'@typescript-eslint/types': 5.30.6
'@typescript-eslint/typescript-estree': 5.30.6(typescript@4.7.4)
debug: 4.3.4(supports-color@9.2.2)
eslint: 8.28.0
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser@5.45.0(eslint@8.24.0)(typescript@4.7.4):
resolution: {integrity: sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7875,26 +7686,6 @@ packages:
- supports-color
dev: true
/@typescript-eslint/parser@5.45.0(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 5.45.0
'@typescript-eslint/types': 5.45.0
'@typescript-eslint/typescript-estree': 5.45.0(typescript@4.7.4)
debug: 4.3.4(supports-color@9.2.2)
eslint: 8.28.0
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser@5.45.0(eslint@8.29.0)(typescript@4.9.3):
resolution: {integrity: sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7969,25 +7760,6 @@ packages:
- supports-color
dev: true
/@typescript-eslint/type-utils@5.30.6(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '*'
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/utils': 5.30.6(eslint@8.28.0)(typescript@4.7.4)
debug: 4.3.4(supports-color@9.2.2)
eslint: 8.28.0
tsutils: 3.21.0(typescript@4.7.4)
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/type-utils@5.45.0(eslint@8.24.0)(typescript@4.7.4):
resolution: {integrity: sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -8008,26 +7780,6 @@ packages:
- supports-color
dev: true
/@typescript-eslint/type-utils@5.45.0(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '*'
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 5.45.0(typescript@4.7.4)
'@typescript-eslint/utils': 5.45.0(eslint@8.28.0)(typescript@4.7.4)
debug: 4.3.4(supports-color@9.2.2)
eslint: 8.28.0
tsutils: 3.21.0(typescript@4.7.4)
typescript: 4.7.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/type-utils@5.45.0(eslint@8.29.0)(typescript@4.9.3):
resolution: {integrity: sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -8157,24 +7909,6 @@ packages:
- typescript
dev: true
/@typescript-eslint/utils@5.30.6(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@types/json-schema': 7.0.9
'@typescript-eslint/scope-manager': 5.30.6
'@typescript-eslint/types': 5.30.6
'@typescript-eslint/typescript-estree': 5.30.6(typescript@4.7.4)
eslint: 8.28.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0(eslint@8.28.0)
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/utils@5.45.0(eslint@8.24.0)(typescript@4.7.4):
resolution: {integrity: sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -8195,26 +7929,6 @@ packages:
- typescript
dev: true
/@typescript-eslint/utils@5.45.0(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@types/json-schema': 7.0.9
'@types/semver': 7.3.13
'@typescript-eslint/scope-manager': 5.45.0
'@typescript-eslint/types': 5.45.0
'@typescript-eslint/typescript-estree': 5.45.0(typescript@4.7.4)
eslint: 8.28.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0(eslint@8.28.0)
semver: 7.3.8
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/utils@5.45.0(eslint@8.29.0)(typescript@4.9.3):
resolution: {integrity: sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -8667,27 +8381,6 @@ packages:
- supports-color
dev: true
/@vue/eslint-config-typescript@11.0.1(eslint-plugin-vue@9.5.1)(eslint@8.28.0)(typescript@4.7.4):
resolution: {integrity: sha512-0U+nL0nA7ahnGPk3rTN49x76miUwuQtQPQNWOFvAcjg6nFJkIkA8qbGNtXwsuHtwBwRtWpHhShL3zK07v+632w==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
eslint-plugin-vue: ^9.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/eslint-plugin': 5.45.0(@typescript-eslint/parser@5.45.0)(eslint@8.28.0)(typescript@4.7.4)
'@typescript-eslint/parser': 5.45.0(eslint@8.28.0)(typescript@4.7.4)
eslint: 8.28.0
eslint-plugin-vue: 9.5.1(eslint@8.28.0)
typescript: 4.7.4
vue-eslint-parser: 9.1.0(eslint@8.28.0)
transitivePeerDependencies:
- supports-color
dev: true
/@vue/eslint-config-typescript@11.0.1(eslint-plugin-vue@9.5.1)(eslint@8.29.0)(typescript@4.9.3):
resolution: {integrity: sha512-0U+nL0nA7ahnGPk3rTN49x76miUwuQtQPQNWOFvAcjg6nFJkIkA8qbGNtXwsuHtwBwRtWpHhShL3zK07v+632w==}
engines: {node: ^14.17.0 || >=16.0.0}
@@ -12172,24 +11865,6 @@ packages:
- supports-color
dev: true
/eslint-plugin-vue@9.5.1(eslint@8.28.0):
resolution: {integrity: sha512-Y0sL2RY7Xc9S8kNih9lbwHIDmewUg9bfas6WSzsOWRgDXhIHKxRBZYNAnVcXBFfE+bMWHUA5GLChl7TcTYUI8w==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
dependencies:
eslint: 8.28.0
eslint-utils: 3.0.0(eslint@8.28.0)
natural-compare: 1.4.0
nth-check: 2.1.1
postcss-selector-parser: 6.0.10
semver: 7.3.7
vue-eslint-parser: 9.1.0(eslint@8.28.0)
xml-name-validator: 4.0.0
transitivePeerDependencies:
- supports-color
dev: true
/eslint-plugin-vue@9.5.1(eslint@8.29.0):
resolution: {integrity: sha512-Y0sL2RY7Xc9S8kNih9lbwHIDmewUg9bfas6WSzsOWRgDXhIHKxRBZYNAnVcXBFfE+bMWHUA5GLChl7TcTYUI8w==}
engines: {node: ^14.17.0 || >=16.0.0}
@@ -12249,16 +11924,6 @@ packages:
eslint-visitor-keys: 2.1.0
dev: true
/eslint-utils@3.0.0(eslint@8.28.0):
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
peerDependencies:
eslint: '>=5'
dependencies:
eslint: 8.28.0
eslint-visitor-keys: 2.1.0
dev: true
/eslint-utils@3.0.0(eslint@8.29.0):
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
@@ -12373,54 +12038,6 @@ packages:
- supports-color
dev: true
/eslint@8.28.0:
resolution: {integrity: sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@eslint/eslintrc': 1.3.3
'@humanwhocodes/config-array': 0.11.7
'@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
debug: 4.3.4(supports-color@9.2.2)
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.1.1
eslint-utils: 3.0.0(eslint@8.28.0)
eslint-visitor-keys: 3.3.0
espree: 9.4.0
esquery: 1.4.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
find-up: 5.0.0
glob-parent: 6.0.2
globals: 13.16.0
grapheme-splitter: 1.0.4
ignore: 5.2.0
import-fresh: 3.3.0
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
js-sdsl: 4.1.4
js-yaml: 4.1.0
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.1
regexpp: 3.2.0
strip-ansi: 6.0.1
strip-json-comments: 3.1.1
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
dev: true
/eslint@8.29.0:
resolution: {integrity: sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -21461,24 +21078,6 @@ packages:
- supports-color
dev: true
/vue-eslint-parser@9.1.0(eslint@8.28.0):
resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '>=6.0.0'
dependencies:
debug: 4.3.4(supports-color@9.2.2)
eslint: 8.28.0
eslint-scope: 7.1.1
eslint-visitor-keys: 3.3.0
espree: 9.4.0
esquery: 1.4.0
lodash: 4.17.21
semver: 7.3.8
transitivePeerDependencies:
- supports-color
dev: true
/vue-eslint-parser@9.1.0(eslint@8.29.0):
resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}
engines: {node: ^14.17.0 || >=16.0.0}
@@ -21614,17 +21213,6 @@ packages:
typescript: 4.9.3
dev: true
/vue-tsc@1.0.9(typescript@4.7.4):
resolution: {integrity: sha512-vRmHD1K6DmBymNhoHjQy/aYKTRQNLGOu2/ESasChG9Vy113K6CdP0NlhR0bzgFJfv2eFB9Ez/9L5kIciUajBxQ==}
hasBin: true
peerDependencies:
typescript: '*'
dependencies:
'@volar/vue-language-core': 1.0.9
'@volar/vue-typescript': 1.0.9
typescript: 4.7.4
dev: true
/vue-tsc@1.0.9(typescript@4.9.3):
resolution: {integrity: sha512-vRmHD1K6DmBymNhoHjQy/aYKTRQNLGOu2/ESasChG9Vy113K6CdP0NlhR0bzgFJfv2eFB9Ez/9L5kIciUajBxQ==}
hasBin: true