Turn on Share Link in nightly builds (#5153)

* WIP: Turn on link sharing in released apps with electron-builder
Fixes #5136

* Add import.meta.env defaults

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Add convenience scripts for windows development; fix protocol name for electron; enable share cmd

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Force release builds

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Trigger CI

* Fix lint

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* CSC_FOR_PULL_REQUEST: true for release build testing

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Adding ://

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Back to debug builds

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Back to debug builds

* WIP: origin

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* To revert: Add logs and custom package version for easier testing

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* More messing with env vars

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Messing with help from deep links docs

* Removed alerts

* Working on macos

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Working second window on windows. Cold start not yet working

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Handle windows cold start

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Clean up after macos testing

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Replace tron:package (Forge) with tronb📦dev (Builder) for e2e

* Add new env var for web app link

* tronb:vite:dev for e2e

* Remove app.requestSingleInstanceLock() call

* Fix unit test

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Revert snap changes

* Only nightly at first

* Remove test app

* Update package.json

* Update src/main.ts

* Remove fetch:wasm:windows

* Final line

* Clean up

* Back to test app for final test

* Fix tsc

* Back to https://app.dev.zoo.dev from vercel branch deploy

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Pierre Jacquier
2025-02-03 10:03:41 -05:00
committed by GitHub
parent ce62fe67cf
commit a44516bc7e
18 changed files with 107 additions and 84 deletions

View File

@ -2,8 +2,8 @@ NODE_ENV=development
DEV=true
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
BASE_URL=https://api.dev.zoo.dev
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev
VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=5000
# ONLY add your token in .env.development.local if you want to skip auth, otherwise this token takes precedence!

View File

@ -1,5 +1,8 @@
NODE_ENV=production
DEV=false
VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.zoo.dev
VITE_KC_SITE_BASE_URL=https://zoo.dev
VITE_KC_SITE_APP_URL=https://app.zoo.dev
VITE_KC_SKIP_AUTH=false
VITE_KC_CONNECTION_TIMEOUT_MS=15000

View File

@ -134,8 +134,6 @@ jobs:
max_attempts: 3
command: yarn install
- run: yarn tronb:vite
- name: Prepare certificate and variables (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
run: |
@ -165,8 +163,8 @@ jobs:
- name: Build the app (debug)
if: ${{ env.IS_RELEASE == 'false' && env.IS_NIGHTLY == 'false' }}
# electron-builder doesn't have a concept of release vs debug,
# this is just not doing any codesign or release yml generation
run: yarn electron-builder --config
# this is just not doing any codesign or release yml generation, and points to dev infra
run: yarn tronb:package:dev
- name: Build the app (release)
if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }}
@ -185,7 +183,7 @@ jobs:
with:
timeout_minutes: 10
max_attempts: 3
command: yarn electron-builder --config --publish always
command: yarn tronb:package:prod
- name: List artifacts in out/
run: ls -R out
@ -246,7 +244,7 @@ jobs:
with:
timeout_minutes: 10
max_attempts: 3
command: yarn electron-builder --config --publish always
command: yarn tronb:package:prod
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}

View File

@ -123,9 +123,9 @@ jobs:
if: steps.download-wasm.outcome == 'failure'
shell: bash
run: yarn build:wasm
- name: build electron
- name: build web
shell: bash
run: yarn tron:package
run: yarn tronb:vite:dev
# - name: Run ubuntu/chrome snapshots
# if: ${{ matrix.os == 'namespace-profile-ubuntu-8-cores' && matrix.shardIndex == 1 }}
# shell: bash

View File

@ -101,7 +101,7 @@ This will start the application and hot-reload on changes.
Devtools can be opened with the usual Cmd-Opt-I (Mac) or Ctrl-Shift-I (Linux and Windows).
To build, run `yarn tron:package`.
To build with electron-builder, run `yarn tronb:package:dev` (or `yarn tronb:package:prod` to point to the .env.production variables)
## Checking out commits / Bisecting

View File

@ -75,3 +75,6 @@ publish:
channel: latest
releaseInfo:
releaseNotesFile: release-notes.md
protocols:
- name: Zoo Studio
schemes: ['zoo-studio']

View File

@ -9,23 +9,8 @@ const rootDir = process.cwd()
const config: ForgeConfig = {
packagerConfig: {
asar: true,
osxSign: (process.env.BUILD_RELEASE === 'true' && {}) || undefined,
osxNotarize:
(process.env.BUILD_RELEASE === 'true' && {
appleId: process.env.APPLE_ID || '',
appleIdPassword: process.env.APPLE_PASSWORD || '',
teamId: process.env.APPLE_TEAM_ID || '',
}) ||
undefined,
executableName: 'zoo-modeling-app',
icon: path.resolve(rootDir, 'assets', 'icon'),
protocols: [
{
name: 'Zoo Studio',
schemes: ['zoo-studio'],
},
],
extendInfo: 'Info.plist', // Information for file associations.
},
rebuildConfig: {},
makers: [],

1
interface.d.ts vendored
View File

@ -65,6 +65,7 @@ export interface IElectronAPI {
VITE_KC_API_WS_MODELING_URL: string
VITE_KC_API_BASE_URL: string
VITE_KC_SITE_BASE_URL: string
VITE_KC_SITE_APP_URL: string
VITE_KC_SKIP_AUTH: string
VITE_KC_CONNECTION_TIMEOUT_MS: string
VITE_KC_DEV_TOKEN: string

View File

@ -103,11 +103,11 @@
"make:dev": "make dev",
"generate:machine-api": "npx openapi-typescript ./openapi/machine-api.json -o src/lib/machine-api.d.ts",
"tron:start": "electron-forge start",
"tron:package": "electron-forge package",
"chrome:test": "PLATFORM=web NODE_ENV=development yarn playwright test --config=playwright.config.ts --project='Google Chrome' --grep-invert='@snapshot'",
"tron:test": "NODE_ENV=development yarn playwright test --config=playwright.electron.config.ts --grep-invert='@snapshot'",
"tronb:vite": "vite build -c vite.main.config.ts && vite build -c vite.preload.config.ts && vite build -c vite.renderer.config.ts",
"tronb:package": "electron-builder --config electron-builder.yml",
"tronb:vite:dev": "vite build -c vite.main.config.ts -m development && vite build -c vite.preload.config.ts -m development && vite build -c vite.renderer.config.ts -m development",
"tronb:vite:prod": "vite build -c vite.main.config.ts && vite build -c vite.preload.config.ts && vite build -c vite.renderer.config.ts",
"tronb:package:dev": "yarn tronb:vite:dev && electron-builder --config electron-builder.yml",
"tronb:package:prod": "yarn tronb:vite:prod && electron-builder --config electron-builder.yml --publish always",
"test-setup": "yarn install && yarn build:wasm",
"test": "vitest --mode development",
"test:unit": "vitest run --mode development --exclude **/kclSamples.test.ts",
@ -116,10 +116,10 @@
"test:playwright:electron:windows": "playwright test --config=playwright.electron.config.ts --grep-invert=\"@skipWin|@snapshot\" --quiet",
"test:playwright:electron:macos": "playwright test --config=playwright.electron.config.ts --grep-invert='@skipMacos|@snapshot' --quiet",
"test:playwright:electron:ubuntu": "playwright test --config=playwright.electron.config.ts --grep-invert='@skipLinux|@snapshot' --quiet",
"test:playwright:electron:local": "yarn tron:package && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@snapshot'",
"test:playwright:electron:windows:local": "yarn tron:package && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert=\"@skipWin|@snapshot\"",
"test:playwright:electron:macos:local": "yarn tron:package && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@skipMacos|@snapshot'",
"test:playwright:electron:ubuntu:local": "yarn tron:package && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@skipLinux|@snapshot'",
"test:playwright:electron:local": "yarn tronb:package:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@snapshot'",
"test:playwright:electron:windows:local": "yarn tronb:package:dev && set NODE_ENV='development' && playwright test --config=playwright.electron.config.ts --grep-invert=\"@skipWin|@snapshot\"",
"test:playwright:electron:macos:local": "yarn tronb:package:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@skipMacos|@snapshot'",
"test:playwright:electron:ubuntu:local": "yarn tronb:package:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@skipLinux|@snapshot'",
"test:unit:local": "yarn simpleserver:bg && yarn test:unit; kill-port 3000",
"test:unit:kcl-samples:local": "yarn simpleserver:bg && yarn test:unit:kcl-samples; kill-port 3000"
},

View File

@ -33,7 +33,7 @@ export const OpenInDesktopAppHandler = (props: React.PropsWithChildren) => {
function onOpenInDesktopApp() {
const newSearchParams = new URLSearchParams(globalThis.location.search)
newSearchParams.delete(ASK_TO_OPEN_QUERY_PARAM)
const newURL = `${ZOO_STUDIO_PROTOCOL}${globalThis.location.pathname.replace(
const newURL = `${ZOO_STUDIO_PROTOCOL}://${globalThis.location.pathname.replace(
'/',
''
)}${searchParams.size > 0 ? `?${newSearchParams.toString()}` : ''}`

View File

@ -19,7 +19,7 @@ import { commandBarActor } from 'machines/commandBarMachine'
import { useSelector } from '@xstate/react'
import { copyFileShareLink } from 'lib/links'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { DEV } from 'env'
import { IS_NIGHTLY_OR_DEBUG } from 'routes/Settings'
import { useToken } from 'machines/appMachine'
const ProjectSidebarMenu = ({
@ -112,6 +112,7 @@ function ProjectMenuPopover({
const { onProjectClose } = useLspContext()
const exportCommandInfo = { name: 'Export', groupId: 'modeling' }
const makeCommandInfo = { name: 'Make', groupId: 'modeling' }
const shareCommandInfo = { name: 'share-file-link', groupId: 'code' }
const findCommand = (obj: { name: string; groupId: string }) =>
Boolean(
commands.find((c) => c.name === obj.name && c.groupId === obj.groupId)
@ -193,7 +194,7 @@ function ProjectMenuPopover({
id: 'share-link',
Element: 'button',
children: 'Share link to file',
disabled: !DEV,
disabled: IS_NIGHTLY_OR_DEBUG || !findCommand(shareCommandInfo),
onClick: async () => {
await copyFileShareLink({
token: token ?? '',

View File

@ -10,6 +10,7 @@ export const VITE_KC_API_WS_MODELING_URL = env.VITE_KC_API_WS_MODELING_URL as
| undefined
export const VITE_KC_API_BASE_URL = env.VITE_KC_API_BASE_URL as string
export const VITE_KC_SITE_BASE_URL = env.VITE_KC_SITE_BASE_URL as string
export const VITE_KC_SITE_APP_URL = env.VITE_KC_SITE_APP_URL as string
export const VITE_KC_SKIP_AUTH = env.VITE_KC_SKIP_AUTH as string | undefined
export const VITE_KC_CONNECTION_TIMEOUT_MS =
env.VITE_KC_CONNECTION_TIMEOUT_MS as string | undefined

View File

@ -68,8 +68,6 @@ export const KCL_DEFAULT_DEGREE = `360`
/** localStorage key for the playwright test-specific app settings file */
export const TEST_SETTINGS_FILE_KEY = 'playwright-test-settings'
export const DEFAULT_HOST = 'https://api.zoo.dev'
export const PROD_APP_URL = 'https://app.zoo.dev'
export const SETTINGS_FILE_NAME = 'settings.toml'
export const TOKEN_FILE_NAME = 'token.txt'
export const PROJECT_SETTINGS_FILE_NAME = 'project.toml'
@ -145,7 +143,7 @@ export const VIEW_NAMES_SEMANTIC = {
export const SIDEBAR_BUTTON_SUFFIX = '-pane-button'
/** Custom URL protocol our desktop registers */
export const ZOO_STUDIO_PROTOCOL = 'zoo-studio:'
export const ZOO_STUDIO_PROTOCOL = 'zoo-studio'
/**
* A query parameter that triggers a modal

View File

@ -1,11 +1,13 @@
import { CommandBarOverwriteWarning } from 'components/CommandBarOverwriteWarning'
import { Command, CommandArgumentOption } from './commandTypes'
import { kclManager } from './singletons'
import { codeManager, kclManager } from './singletons'
import { isDesktop } from './isDesktop'
import { FILE_EXT } from './constants'
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
import { reportRejection } from './trap'
import { IndexLoaderData } from './types'
import { IS_NIGHTLY_OR_DEBUG } from 'routes/Settings'
import { copyFileShareLink } from './links'
interface OnSubmitProps {
sampleName: string
@ -132,21 +134,22 @@ export function kclCommands(commandProps: KclCommandConfig): Command[] {
},
},
},
// {
// name: 'share-file-link',
// displayName: 'Share file',
// description: 'Create a link that contains a copy of the current file.',
// groupId: 'code',
// needsReview: false,
// icon: 'link',
// onSubmit: () => {
// copyFileShareLink({
// token: commandProps.authToken,
// code: codeManager.code,
// name: commandProps.projectData.project?.name || '',
// units: commandProps.settings.defaultUnit,
// }).catch(reportRejection)
// },
// },
{
name: 'share-file-link',
displayName: 'Share file',
hide: IS_NIGHTLY_OR_DEBUG ? undefined : 'desktop',
description: 'Create a link that contains a copy of the current file.',
groupId: 'code',
needsReview: false,
icon: 'link',
onSubmit: () => {
copyFileShareLink({
token: commandProps.authToken,
code: codeManager.code,
name: commandProps.projectData.project?.name || '',
units: commandProps.settings.defaultUnit,
}).catch(reportRejection)
},
},
]
}

View File

@ -1,3 +1,4 @@
import { VITE_KC_SITE_APP_URL } from 'env'
import { createCreateFileUrl } from './links'
describe(`link creation tests`, () => {
@ -8,7 +9,7 @@ describe(`link creation tests`, () => {
// Converted with external online tools
const expectedEncodedCode = `ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D`
const expectedLink = `http://localhost:3000/?create-file=true&name=test&units=mm&code=${expectedEncodedCode}&ask-open-desktop=true`
const expectedLink = `${VITE_KC_SITE_APP_URL}/?create-file=true&name=test&units=mm&code=${expectedEncodedCode}&ask-open-desktop=true`
const result = createCreateFileUrl({ code, name, units })
expect(result.toString()).toBe(expectedLink)

View File

@ -1,11 +1,7 @@
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
import {
ASK_TO_OPEN_QUERY_PARAM,
CREATE_FILE_URL_PARAM,
PROD_APP_URL,
} from './constants'
import { ASK_TO_OPEN_QUERY_PARAM, CREATE_FILE_URL_PARAM } from './constants'
import { stringToBase64 } from './base64'
import { DEV, VITE_KC_API_BASE_URL } from 'env'
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_APP_URL } from 'env'
import toast from 'react-hot-toast'
import { err } from './trap'
export interface FileLinkParams {
@ -51,8 +47,7 @@ export async function copyFileShareLink(
* open the URL in the desktop app.
*/
export function createCreateFileUrl({ code, name, units }: FileLinkParams) {
// Use the dev server if we are in development mode
let origin = DEV ? 'http://localhost:3000' : PROD_APP_URL
let origin = VITE_KC_SITE_APP_URL
const searchParams = new URLSearchParams({
[CREATE_FILE_URL_PARAM]: String(true),
name,

View File

@ -31,23 +31,27 @@ let mainWindow: BrowserWindow | null = null
// Check the command line arguments for a project path
const args = parseCLIArgs()
// If it's not set, scream.
const NODE_ENV = process.env.NODE_ENV || 'production'
if (!process.env.NODE_ENV)
console.warn(
'*FOX SCREAM* process.env.NODE_ENV is not explicitly set!, defaulting to production'
)
// Default prod values
// @ts-ignore: TS1343
const viteEnv = import.meta.env
const NODE_ENV = process.env.NODE_ENV || viteEnv.MODE
// dotenv override when present
dotenv.config({ path: [`.env.${NODE_ENV}.local`, `.env.${NODE_ENV}`] })
process.env.VITE_KC_API_WS_MODELING_URL ??=
'wss://api.zoo.dev/ws/modeling/commands'
process.env.VITE_KC_API_BASE_URL ??= 'https://api.zoo.dev'
process.env.VITE_KC_SITE_BASE_URL ??= 'https://zoo.dev'
process.env.VITE_KC_SKIP_AUTH ??= 'false'
process.env.VITE_KC_CONNECTION_TIMEOUT_MS ??= '15000'
// default vite values based on mode
process.env.NODE_ENV ??= viteEnv.MODE
process.env.DEV ??= viteEnv.DEV + ''
process.env.BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL
process.env.VITE_KC_API_WS_MODELING_URL ??= viteEnv.VITE_KC_API_WS_MODELING_URL
process.env.VITE_KC_API_BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL
process.env.VITE_KC_SITE_BASE_URL ??= viteEnv.VITE_KC_SITE_BASE_URL
process.env.VITE_KC_SITE_APP_URL ??= viteEnv.VITE_KC_SITE_APP_URL
process.env.VITE_KC_SKIP_AUTH ??= viteEnv.VITE_KC_SKIP_AUTH
process.env.VITE_KC_CONNECTION_TIMEOUT_MS ??=
viteEnv.VITE_KC_CONNECTION_TIMEOUT_MS
// Likely convenient to keep for debugging
console.log('process.env', process.env)
/// Register our application to handle all "zoo-studio:" protocols.
if (process.defaultApp) {
@ -89,22 +93,43 @@ const createWindow = (pathToOpen?: string, reuse?: boolean): BrowserWindow => {
})
}
// Deep Link: Case of a cold start from Windows or Linux
if (
!pathToOpen &&
process.argv.length > 1 &&
process.argv[1].indexOf(ZOO_STUDIO_PROTOCOL + '://') > -1
) {
pathToOpen = process.argv[1]
console.log('Retrieved deep link from argv', pathToOpen)
}
// Deep Link: Case of a second window opened for macOS
// @ts-ignore
if (!pathToOpen && global['openUrls'] && global['openUrls'][0]) {
// @ts-ignore
pathToOpen = global['openUrls'][0]
console.log('Retrieved deep link from open-url', pathToOpen)
}
const pathIsCustomProtocolLink =
pathToOpen?.startsWith(ZOO_STUDIO_PROTOCOL) ?? false
// and load the index.html of the app.
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
const filteredPath = pathToOpen
? decodeURI(pathToOpen.replace(ZOO_STUDIO_PROTOCOL, ''))
? decodeURI(pathToOpen.replace(ZOO_STUDIO_PROTOCOL + '://', ''))
: ''
const fullHashBasedUrl = `${MAIN_WINDOW_VITE_DEV_SERVER_URL}/#/${filteredPath}`
newWindow.loadURL(fullHashBasedUrl).catch(reportRejection)
} else {
if (pathIsCustomProtocolLink && pathToOpen) {
// We're trying to open a custom protocol link
const filteredPath = pathToOpen
? decodeURI(pathToOpen.replace(ZOO_STUDIO_PROTOCOL, ''))
: ''
// TODO: fix the replace %3 thing
const urlNoProtocol = pathToOpen
.replace(ZOO_STUDIO_PROTOCOL + '://', '')
.replaceAll('%3D', '')
.replaceAll('%3', '')
const filteredPath = decodeURI(urlNoProtocol)
const startIndex = path.join(
__dirname,
`../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`
@ -342,7 +367,7 @@ export function getAutoUpdater(): AppUpdater {
app.on('ready', () => {
// Disable auto updater on non-versioned builds
if (packageJSON.version === '0.0.0') {
if (packageJSON.version === '0.0.0' && viteEnv.MODE !== 'production') {
return
}
@ -459,6 +484,14 @@ function parseCLIArgs(): minimist.ParsedArgs {
}
function registerStartupListeners() {
// Linux and Windows from https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Deep Link: second instance for Windows and Linux
const url = commandLine.pop()?.slice(0, -1)
console.log('Retrieved deep link from commandLine', url)
createWindow(url)
})
/**
* macOS: when someone drops a file to the not-yet running VSCode, the open-file event fires even before
* the app-ready event. We listen very early for open-file and remember this upon startup as path to open.
@ -478,7 +511,7 @@ function registerStartupListeners() {
})
/**
* macOS: react to open-url requests.
* macOS: react to open-url requests (including Deep Link on second instances)
*/
const openUrls: string[] = []
// @ts-ignore

View File

@ -185,6 +185,7 @@ contextBridge.exposeInMainWorld('electron', {
'VITE_KC_API_WS_MODELING_URL',
'VITE_KC_API_BASE_URL',
'VITE_KC_SITE_BASE_URL',
'VITE_KC_SITE_APP_URL',
'VITE_KC_SKIP_AUTH',
'VITE_KC_CONNECTION_TIMEOUT_MS',
'VITE_KC_DEV_TOKEN',