From 9800697670f01c1877c684fbb5c2e46f5049faa0 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Thu, 22 Dec 2022 02:12:37 +0000 Subject: [PATCH] feat: add support for client-side server to tauri module (#501) --- modules/tauri/index.ts | 21 +++++++- modules/tauri/runtime/nitro.client.ts | 71 +++++++++++++++++++++++++++ modules/tauri/runtime/storage.ts | 27 ++++++++++ package.json | 1 + pnpm-lock.yaml | 20 ++++++++ server/api/[server]/login.ts | 1 + server/api/[server]/oauth.ts | 1 + server/shared.ts | 3 +- 8 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 modules/tauri/runtime/nitro.client.ts create mode 100644 modules/tauri/runtime/storage.ts diff --git a/modules/tauri/index.ts b/modules/tauri/index.ts index 94c0b40d..a7429262 100644 --- a/modules/tauri/index.ts +++ b/modules/tauri/index.ts @@ -1,4 +1,4 @@ -import { addPlugin, createResolver, defineNuxtModule, useNuxt } from '@nuxt/kit' +import { addImports, addPlugin, createResolver, defineNuxtModule, useNuxt } from '@nuxt/kit' export default defineNuxtModule({ meta: { @@ -11,11 +11,30 @@ export default defineNuxtModule({ if (!process.env.TAURI_PLATFORM) 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 }) => { config.build!.target = ['es2021', 'chrome100', 'safari13'] 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/nitro.client')) }, }) diff --git a/modules/tauri/runtime/nitro.client.ts b/modules/tauri/runtime/nitro.client.ts new file mode 100644 index 00000000..771901f9 --- /dev/null +++ b/modules/tauri/runtime/nitro.client.ts @@ -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')! + } +}) diff --git a/modules/tauri/runtime/storage.ts b/modules/tauri/runtime/storage.ts new file mode 100644 index 00000000..885b9d75 --- /dev/null +++ b/modules/tauri/runtime/storage.ts @@ -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 diff --git a/package.json b/package.json index a4ec93e1..032abb04 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "shiki": "^0.11.1", "shiki-es": "^0.1.2", "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", "ufo": "^1.0.1", "ultrahtml": "^1.0.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3ef6595a..bc52e5a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,7 @@ specifiers: simple-git-hooks: ^2.8.1 std-env: ^3.3.1 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 tippy.js: ^6.3.7 typescript: ^4.9.3 @@ -95,6 +96,7 @@ dependencies: shiki: 0.11.1 shiki-es: 0.1.2 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 ufo: 1.0.1 ultrahtml: 1.0.4 @@ -2288,6 +2290,11 @@ packages: string.prototype.matchall: 4.0.8 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: resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==} engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} @@ -9193,6 +9200,10 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true + /tslib/2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + dev: false + /tslib/2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} @@ -10420,3 +10431,12 @@ packages: '@tauri-apps/api': 1.2.0 tslib: 2.4.1 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 diff --git a/server/api/[server]/login.ts b/server/api/[server]/login.ts index 3141f31a..ab25416f 100644 --- a/server/api/[server]/login.ts +++ b/server/api/[server]/login.ts @@ -1,4 +1,5 @@ import { stringifyQuery } from 'ufo' +import { createError, defineEventHandler, getRouterParams } from 'h3' import { getApp, getRedirectURI } from '~/server/shared' export default defineEventHandler(async (event) => { diff --git a/server/api/[server]/oauth.ts b/server/api/[server]/oauth.ts index 84f6a4aa..d9159cbe 100644 --- a/server/api/[server]/oauth.ts +++ b/server/api/[server]/oauth.ts @@ -1,4 +1,5 @@ import { stringifyQuery } from 'vue-router' +import { createError, defineEventHandler, getQuery, getRouterParams, sendRedirect } from 'h3' import { getApp, getRedirectURI } from '~/server/shared' export default defineEventHandler(async (event) => { diff --git a/server/shared.ts b/server/shared.ts index 1efa87e1..9daca515 100644 --- a/server/shared.ts +++ b/server/shared.ts @@ -2,6 +2,7 @@ import _fs from 'unstorage/drivers/fs' // @ts-expect-error unstorage needs to provide backwards-compatible subpath types import _kv from 'unstorage/drivers/cloudflare-kv-http' + import { parseURL } from 'ufo' import { $fetch } from 'ofetch' @@ -24,7 +25,7 @@ const storage = useStorage() as Storage if (config.storage.driver === 'fs') { storage.mount('servers', fs({ base: config.storage.fsBase })) } -else { +else if (config.storage.driver === 'cloudflare') { storage.mount('servers', cached(kv({ accountId: config.cloudflare.accountId, namespaceId: config.cloudflare.namespaceId,