feat: add support for client-side server to tauri module (#501)
parent
2b5051e123
commit
9800697670
|
@ -1,4 +1,4 @@
|
||||||
import { addPlugin, createResolver, defineNuxtModule, useNuxt } from '@nuxt/kit'
|
import { addImports, addPlugin, createResolver, defineNuxtModule, useNuxt } from '@nuxt/kit'
|
||||||
|
|
||||||
export default defineNuxtModule({
|
export default defineNuxtModule({
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -11,11 +11,30 @@ export default defineNuxtModule({
|
||||||
if (!process.env.TAURI_PLATFORM)
|
if (!process.env.TAURI_PLATFORM)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (nuxt.options.dev)
|
||||||
|
nuxt.options.ssr = false
|
||||||
|
|
||||||
|
nuxt.options.alias = {
|
||||||
|
...nuxt.options.alias,
|
||||||
|
'unstorage/drivers/fs': 'unenv/runtime/mock/proxy',
|
||||||
|
'unstorage/drivers/cloudflare-kv-http': 'unenv/runtime/mock/proxy',
|
||||||
|
'node:events': 'unenv/runtime/node/events/index',
|
||||||
|
}
|
||||||
|
|
||||||
nuxt.hook('vite:extend', ({ config }) => {
|
nuxt.hook('vite:extend', ({ config }) => {
|
||||||
config.build!.target = ['es2021', 'chrome100', 'safari13']
|
config.build!.target = ['es2021', 'chrome100', 'safari13']
|
||||||
config.envPrefix = [...config.envPrefix || [], 'VITE_', 'TAURI_']
|
config.envPrefix = [...config.envPrefix || [], 'VITE_', 'TAURI_']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// prevent creation of server routes
|
||||||
|
nuxt.hook('nitro:config', (config) => {
|
||||||
|
config.srcDir = './_nonexistent'
|
||||||
|
config.scanDirs = []
|
||||||
|
})
|
||||||
|
|
||||||
|
addImports({ name: 'useStorage', from: resolve('./runtime/storage') })
|
||||||
|
|
||||||
addPlugin(resolve('./runtime/logging.client'))
|
addPlugin(resolve('./runtime/logging.client'))
|
||||||
|
addPlugin(resolve('./runtime/nitro.client'))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import {
|
||||||
|
createApp,
|
||||||
|
createRouter,
|
||||||
|
defineLazyEventHandler,
|
||||||
|
toNodeListener,
|
||||||
|
} from 'h3'
|
||||||
|
import { createFetch } from 'ofetch'
|
||||||
|
import { parseURL } from 'ufo'
|
||||||
|
import {
|
||||||
|
createCall,
|
||||||
|
createFetch as createLocalFetch,
|
||||||
|
} from 'unenv/runtime/fetch/index'
|
||||||
|
|
||||||
|
const handlers = [
|
||||||
|
{
|
||||||
|
route: '/api/:server/oauth',
|
||||||
|
handler: defineLazyEventHandler(() => import('~/server/api/[server]/oauth').then(r => r.default || r)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
route: '/api/:server/login',
|
||||||
|
handler: defineLazyEventHandler(() => import('~/server/api/[server]/login').then(r => r.default || r)),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const { protocol, host } = parseURL(window.location.href)
|
||||||
|
|
||||||
|
// @ts-expect-error undeclared global window property
|
||||||
|
window.__NUXT__.config = {
|
||||||
|
// @ts-expect-error undeclared global window property
|
||||||
|
...window.__NUXT__.config,
|
||||||
|
deployUrl: `${protocol}//${host}`,
|
||||||
|
storage: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineNuxtPlugin(async () => {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
|
||||||
|
const h3App = createApp({
|
||||||
|
debug: process.dev,
|
||||||
|
// TODO: add global error handler
|
||||||
|
// onError: (err, event) => {
|
||||||
|
// console.log({ err, event })
|
||||||
|
// },
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = createRouter()
|
||||||
|
|
||||||
|
for (const h of handlers)
|
||||||
|
router.use(h.route, h.handler)
|
||||||
|
|
||||||
|
// @ts-expect-error TODO: fix
|
||||||
|
h3App.use(config.app.baseURL, router)
|
||||||
|
|
||||||
|
const localCall = createCall(toNodeListener(h3App) as any)
|
||||||
|
const localFetch = createLocalFetch(localCall, globalThis.fetch)
|
||||||
|
|
||||||
|
// @ts-expect-error slight differences in api
|
||||||
|
globalThis.$fetch = createFetch({
|
||||||
|
// @ts-expect-error slight differences in api
|
||||||
|
fetch: localFetch,
|
||||||
|
Headers,
|
||||||
|
defaults: { baseURL: config.app.baseURL },
|
||||||
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
if (route.path.startsWith('/api')) {
|
||||||
|
const result = await $fetch.raw(route.fullPath)
|
||||||
|
if (result.headers.get('location'))
|
||||||
|
location.href = result.headers.get('location')!
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { createStorage } from 'unstorage'
|
||||||
|
import { Store } from 'tauri-plugin-store-api'
|
||||||
|
|
||||||
|
const store = new Store('.servers.dat')
|
||||||
|
const storage = createStorage()
|
||||||
|
storage.mount('servers', {
|
||||||
|
getKeys() {
|
||||||
|
return store.keys()
|
||||||
|
},
|
||||||
|
async removeItem(key: string) {
|
||||||
|
await store.delete(key)
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
return store.clear()
|
||||||
|
},
|
||||||
|
hasItem(key: string) {
|
||||||
|
return store.has(key)
|
||||||
|
},
|
||||||
|
setItem(key: string, value: any) {
|
||||||
|
return store.set(key, value)
|
||||||
|
},
|
||||||
|
getItem(key: string) {
|
||||||
|
return store.get(key)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const useStorage = () => storage
|
|
@ -48,6 +48,7 @@
|
||||||
"shiki": "^0.11.1",
|
"shiki": "^0.11.1",
|
||||||
"shiki-es": "^0.1.2",
|
"shiki-es": "^0.1.2",
|
||||||
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log",
|
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log",
|
||||||
|
"tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"ufo": "^1.0.1",
|
"ufo": "^1.0.1",
|
||||||
"ultrahtml": "^1.0.4",
|
"ultrahtml": "^1.0.4",
|
||||||
|
|
|
@ -56,6 +56,7 @@ specifiers:
|
||||||
simple-git-hooks: ^2.8.1
|
simple-git-hooks: ^2.8.1
|
||||||
std-env: ^3.3.1
|
std-env: ^3.3.1
|
||||||
tauri-plugin-log-api: github:tauri-apps/tauri-plugin-log
|
tauri-plugin-log-api: github:tauri-apps/tauri-plugin-log
|
||||||
|
tauri-plugin-store-api: github:tauri-apps/tauri-plugin-store
|
||||||
theme-vitesse: ^0.6.0
|
theme-vitesse: ^0.6.0
|
||||||
tippy.js: ^6.3.7
|
tippy.js: ^6.3.7
|
||||||
typescript: ^4.9.3
|
typescript: ^4.9.3
|
||||||
|
@ -95,6 +96,7 @@ dependencies:
|
||||||
shiki: 0.11.1
|
shiki: 0.11.1
|
||||||
shiki-es: 0.1.2
|
shiki-es: 0.1.2
|
||||||
tauri-plugin-log-api: github.com/tauri-apps/tauri-plugin-log/b58475bbc410fa78eb69276c62d0b64c91c07914
|
tauri-plugin-log-api: github.com/tauri-apps/tauri-plugin-log/b58475bbc410fa78eb69276c62d0b64c91c07914
|
||||||
|
tauri-plugin-store-api: github.com/tauri-apps/tauri-plugin-store/9bd993aa67766596638bbfd91e79a1bf8f632014
|
||||||
tippy.js: 6.3.7
|
tippy.js: 6.3.7
|
||||||
ufo: 1.0.1
|
ufo: 1.0.1
|
||||||
ultrahtml: 1.0.4
|
ultrahtml: 1.0.4
|
||||||
|
@ -2288,6 +2290,11 @@ packages:
|
||||||
string.prototype.matchall: 4.0.8
|
string.prototype.matchall: 4.0.8
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@tauri-apps/api/1.1.0:
|
||||||
|
resolution: {integrity: sha512-n13pIqdPd3KtaMmmAcrU7BTfdMtIlGNnfZD0dNX8L4p8dgmuNyikm6JAA+yCpl9gqq6I8x5cV2Y0muqdgD0cWw==}
|
||||||
|
engines: {node: '>= 12.22.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@tauri-apps/api/1.2.0:
|
/@tauri-apps/api/1.2.0:
|
||||||
resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==}
|
resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==}
|
||||||
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
||||||
|
@ -9193,6 +9200,10 @@ packages:
|
||||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/tslib/2.4.0:
|
||||||
|
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/tslib/2.4.1:
|
/tslib/2.4.1:
|
||||||
resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
|
resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
|
||||||
|
|
||||||
|
@ -10420,3 +10431,12 @@ packages:
|
||||||
'@tauri-apps/api': 1.2.0
|
'@tauri-apps/api': 1.2.0
|
||||||
tslib: 2.4.1
|
tslib: 2.4.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
github.com/tauri-apps/tauri-plugin-store/9bd993aa67766596638bbfd91e79a1bf8f632014:
|
||||||
|
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-store/tar.gz/9bd993aa67766596638bbfd91e79a1bf8f632014}
|
||||||
|
name: tauri-plugin-store-api
|
||||||
|
version: 0.1.0
|
||||||
|
dependencies:
|
||||||
|
'@tauri-apps/api': 1.1.0
|
||||||
|
tslib: 2.4.0
|
||||||
|
dev: false
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { stringifyQuery } from 'ufo'
|
import { stringifyQuery } from 'ufo'
|
||||||
|
import { createError, defineEventHandler, getRouterParams } from 'h3'
|
||||||
import { getApp, getRedirectURI } from '~/server/shared'
|
import { getApp, getRedirectURI } from '~/server/shared'
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { stringifyQuery } from 'vue-router'
|
import { stringifyQuery } from 'vue-router'
|
||||||
|
import { createError, defineEventHandler, getQuery, getRouterParams, sendRedirect } from 'h3'
|
||||||
import { getApp, getRedirectURI } from '~/server/shared'
|
import { getApp, getRedirectURI } from '~/server/shared'
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import _fs from 'unstorage/drivers/fs'
|
import _fs from 'unstorage/drivers/fs'
|
||||||
// @ts-expect-error unstorage needs to provide backwards-compatible subpath types
|
// @ts-expect-error unstorage needs to provide backwards-compatible subpath types
|
||||||
import _kv from 'unstorage/drivers/cloudflare-kv-http'
|
import _kv from 'unstorage/drivers/cloudflare-kv-http'
|
||||||
|
|
||||||
import { parseURL } from 'ufo'
|
import { parseURL } from 'ufo'
|
||||||
|
|
||||||
import { $fetch } from 'ofetch'
|
import { $fetch } from 'ofetch'
|
||||||
|
@ -24,7 +25,7 @@ const storage = useStorage() as Storage
|
||||||
if (config.storage.driver === 'fs') {
|
if (config.storage.driver === 'fs') {
|
||||||
storage.mount('servers', fs({ base: config.storage.fsBase }))
|
storage.mount('servers', fs({ base: config.storage.fsBase }))
|
||||||
}
|
}
|
||||||
else {
|
else if (config.storage.driver === 'cloudflare') {
|
||||||
storage.mount('servers', cached(kv({
|
storage.mount('servers', cached(kv({
|
||||||
accountId: config.cloudflare.accountId,
|
accountId: config.cloudflare.accountId,
|
||||||
namespaceId: config.cloudflare.namespaceId,
|
namespaceId: config.cloudflare.namespaceId,
|
||||||
|
|
Loading…
Reference in New Issue