feat: version 1.0.0 (#21)
This commit is contained in:
@ -1,3 +1,3 @@
|
||||
export const PATH = '/__nuxt_mongoose__'
|
||||
export const PATH_CLIENT = `${PATH}/client`
|
||||
export const WS_EVENT_NAME = 'nuxt:devtools:mongoose:rpc'
|
||||
export const CLIENT_PATH = '/__nuxt-mongoose'
|
||||
export const CLIENT_PORT = 3300
|
||||
export const RPC_NAMESPACE = 'nuxt-mongoose-rpc'
|
||||
|
||||
56
src/devtools.ts
Normal file
56
src/devtools.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import type { Resolver } from '@nuxt/kit'
|
||||
import { extendServerRpc, onDevToolsInitialized } from '@nuxt/devtools-kit'
|
||||
import type { ClientFunctions, ServerFunctions } from './types'
|
||||
import type { ModuleOptions } from './module'
|
||||
import { useViteWebSocket } from './utils'
|
||||
|
||||
import { setupRPC } from './rpc'
|
||||
import { CLIENT_PATH, CLIENT_PORT, RPC_NAMESPACE } from './constants'
|
||||
|
||||
export function setupDevToolsUI(options: ModuleOptions, resolve: Resolver['resolve'], nuxt: Nuxt) {
|
||||
const clientPath = resolve('./client')
|
||||
const isProductionBuild = existsSync(clientPath)
|
||||
|
||||
if (isProductionBuild) {
|
||||
nuxt.hook('vite:serverCreated', async (server) => {
|
||||
const sirv = await import('sirv').then(r => r.default || r)
|
||||
server.middlewares.use(
|
||||
CLIENT_PATH,
|
||||
sirv(clientPath, { dev: true, single: true }),
|
||||
)
|
||||
})
|
||||
}
|
||||
else {
|
||||
nuxt.hook('vite:extendConfig', (config) => {
|
||||
config.server = config.server || {}
|
||||
config.server.proxy = config.server.proxy || {}
|
||||
config.server.proxy[CLIENT_PATH] = {
|
||||
target: `http://localhost:${CLIENT_PORT}${CLIENT_PATH}`,
|
||||
changeOrigin: true,
|
||||
followRedirects: true,
|
||||
rewrite: path => path.replace(CLIENT_PATH, ''),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
nuxt.hook('devtools:customTabs', (tabs) => {
|
||||
tabs.push({
|
||||
name: 'nuxt-mongoose',
|
||||
title: 'Mongoose',
|
||||
icon: 'skill-icons:mongodb',
|
||||
view: {
|
||||
type: 'iframe',
|
||||
src: CLIENT_PATH,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
const wsServer = useViteWebSocket(nuxt)
|
||||
onDevToolsInitialized(async () => {
|
||||
const rpcFunctions = setupRPC({ options, wsServer, nuxt })
|
||||
|
||||
extendServerRpc<ClientFunctions, ServerFunctions>(RPC_NAMESPACE, rpcFunctions)
|
||||
})
|
||||
}
|
||||
118
src/module.ts
118
src/module.ts
@ -1,25 +1,46 @@
|
||||
import {
|
||||
addImportsDir,
|
||||
addServerPlugin,
|
||||
addTemplate,
|
||||
addVitePlugin,
|
||||
createResolver,
|
||||
defineNuxtModule,
|
||||
logger,
|
||||
} from '@nuxt/kit'
|
||||
import { pathExists } from 'fs-extra'
|
||||
import type { ConnectOptions } from 'mongoose'
|
||||
import defu from 'defu'
|
||||
import { join } from 'pathe'
|
||||
import { defu } from 'defu'
|
||||
import sirv from 'sirv'
|
||||
import { $fetch } from 'ofetch'
|
||||
import { version } from '../package.json'
|
||||
import { setupDevToolsUI } from './devtools'
|
||||
|
||||
import { PATH_CLIENT } from './constants'
|
||||
import type { ModuleOptions } from './types'
|
||||
|
||||
import { setupRPC } from './server-rpc'
|
||||
|
||||
export type { ModuleOptions }
|
||||
export interface ModuleOptions {
|
||||
/**
|
||||
* The MongoDB URI connection
|
||||
*
|
||||
* @default process.env.MONGODB_URI
|
||||
*
|
||||
*/
|
||||
uri: string | undefined
|
||||
/**
|
||||
* Nuxt DevTools
|
||||
*
|
||||
* @default true
|
||||
*
|
||||
*/
|
||||
devtools: boolean
|
||||
/**
|
||||
* Mongoose Connections
|
||||
*
|
||||
* @default {}
|
||||
*/
|
||||
options?: ConnectOptions
|
||||
/**
|
||||
* Models Directory for auto-import
|
||||
*
|
||||
* @default 'models'
|
||||
*
|
||||
*/
|
||||
modelsDir?: string
|
||||
}
|
||||
|
||||
export default defineNuxtModule<ModuleOptions>({
|
||||
meta: {
|
||||
@ -27,15 +48,13 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
configKey: 'mongoose',
|
||||
},
|
||||
defaults: {
|
||||
// eslint-disable-next-line n/prefer-global/process
|
||||
uri: process.env.MONGODB_URI as string,
|
||||
devtools: true,
|
||||
options: {},
|
||||
modelsDir: 'models',
|
||||
},
|
||||
setup(options, nuxt) {
|
||||
const { resolve } = createResolver(import.meta.url)
|
||||
const runtimeConfig = nuxt.options.runtimeConfig as any
|
||||
|
||||
async setup(options, nuxt) {
|
||||
if (nuxt.options.dev) {
|
||||
$fetch('https://registry.npmjs.org/nuxt-mongoose/latest').then((release) => {
|
||||
if (release.version > version)
|
||||
@ -43,62 +62,35 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
addImportsDir(resolve('./runtime/composables'))
|
||||
|
||||
if (!options.uri) {
|
||||
logger.warn('Missing `MONGODB_URI` in `.env`')
|
||||
logger.warn('Missing MongoDB URI. You can set it in your `nuxt.config` or in your `.env` as `MONGODB_URI`')
|
||||
return
|
||||
}
|
||||
|
||||
// Runtime Config
|
||||
runtimeConfig.mongoose = defu(runtimeConfig.mongoose || {}, {
|
||||
const { resolve } = createResolver(import.meta.url)
|
||||
const config = nuxt.options.runtimeConfig as any
|
||||
|
||||
config.mongoose = defu(config.mongoose || {}, {
|
||||
uri: options.uri,
|
||||
options: options.options,
|
||||
devtools: options.devtools,
|
||||
modelsDir: options.modelsDir,
|
||||
})
|
||||
|
||||
// Setup devtools UI
|
||||
const distResolve = (p: string) => {
|
||||
const cwd = resolve('.')
|
||||
if (cwd.endsWith('/dist'))
|
||||
return resolve(p)
|
||||
return resolve(`../dist/${p}`)
|
||||
}
|
||||
|
||||
const clientPath = distResolve('./client')
|
||||
const { vitePlugin } = setupRPC(nuxt, options)
|
||||
|
||||
addVitePlugin(vitePlugin)
|
||||
|
||||
nuxt.hook('vite:serverCreated', async (server) => {
|
||||
if (await pathExists(clientPath))
|
||||
server.middlewares.use(PATH_CLIENT, sirv(clientPath, { dev: true, single: true }))
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
|
||||
// @ts-ignore runtime type
|
||||
nuxt.hook('devtools:customTabs', (iframeTabs) => {
|
||||
iframeTabs.push({
|
||||
name: 'mongoose',
|
||||
title: 'Mongoose',
|
||||
icon: 'skill-icons:mongodb',
|
||||
view: {
|
||||
type: 'iframe',
|
||||
src: PATH_CLIENT,
|
||||
},
|
||||
})
|
||||
modelsDir: join(nuxt.options.serverDir, options.modelsDir!),
|
||||
})
|
||||
|
||||
// virtual imports
|
||||
nuxt.hook('nitro:config', (nitroConfig) => {
|
||||
nitroConfig.alias = nitroConfig.alias || {}
|
||||
nuxt.hook('nitro:config', (_config) => {
|
||||
_config.alias = _config.alias || {}
|
||||
|
||||
// Inline module runtime in Nitro bundle
|
||||
nitroConfig.externals = defu(typeof nitroConfig.externals === 'object' ? nitroConfig.externals : {}, {
|
||||
_config.externals = defu(typeof _config.externals === 'object' ? _config.externals : {}, {
|
||||
inline: [resolve('./runtime')],
|
||||
})
|
||||
nitroConfig.alias['#nuxt/mongoose'] = resolve('./runtime/server/services')
|
||||
_config.alias['#nuxt/mongoose'] = resolve('./runtime/server/services')
|
||||
|
||||
if (_config.imports) {
|
||||
_config.imports.dirs = _config.imports.dirs || []
|
||||
_config.imports.dirs?.push(config.mongoose.modelsDir)
|
||||
}
|
||||
})
|
||||
|
||||
addTemplate({
|
||||
@ -115,15 +107,9 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
options.references.push({ path: resolve(nuxt.options.buildDir, 'types/nuxt-mongoose.d.ts') })
|
||||
})
|
||||
|
||||
// Nitro auto imports
|
||||
nuxt.hook('nitro:config', (_nitroConfig) => {
|
||||
if (_nitroConfig.imports) {
|
||||
_nitroConfig.imports.dirs = _nitroConfig.imports.dirs || []
|
||||
_nitroConfig.imports.dirs?.push(
|
||||
join(nuxt.options.serverDir, runtimeConfig.mongoose.modelsDir),
|
||||
)
|
||||
}
|
||||
})
|
||||
const isDevToolsEnabled = typeof nuxt.options.devtools === 'boolean' ? nuxt.options.devtools : nuxt.options.devtools.enabled
|
||||
if (nuxt.options.dev && isDevToolsEnabled)
|
||||
setupDevToolsUI(options, resolve, nuxt)
|
||||
|
||||
// Add server-plugin for database connection
|
||||
addServerPlugin(resolve('./runtime/server/plugins/mongoose.db'))
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import mongoose from 'mongoose'
|
||||
import type { NuxtDevtoolsServerContext, ServerFunctions } from '../types'
|
||||
|
||||
export function setupDatabaseRPC({ options }: NuxtDevtoolsServerContext): any {
|
||||
mongoose.connect(options.uri, options.options)
|
||||
import type { DevtoolsServerContext, ServerFunctions } from '../types'
|
||||
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
export function setupDatabaseRPC({}: DevtoolsServerContext) {
|
||||
return {
|
||||
async readyState() {
|
||||
return mongoose.connection.readyState
|
||||
@ -62,8 +61,8 @@ export function setupDatabaseRPC({ options }: NuxtDevtoolsServerContext): any {
|
||||
const skip = (options.page - 1) * options.limit
|
||||
const cursor = mongoose.connection.db.collection(collection).find().skip(skip)
|
||||
if (options.limit !== 0)
|
||||
cursor.limit(options.limit)
|
||||
return await cursor.toArray()
|
||||
cursor?.limit(options.limit)
|
||||
return await cursor?.toArray()
|
||||
},
|
||||
async getDocument(collection: string, document: any) {
|
||||
try {
|
||||
23
src/rpc/index.ts
Normal file
23
src/rpc/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import mongoose from 'mongoose'
|
||||
import type { DevtoolsServerContext, ServerFunctions } from '../types'
|
||||
|
||||
import { setupDatabaseRPC } from './database'
|
||||
import { setupResourceRPC } from './resource'
|
||||
|
||||
export function setupRPC(ctx: DevtoolsServerContext): ServerFunctions {
|
||||
mongoose.connect(ctx.options.uri, ctx.options.options)
|
||||
|
||||
return {
|
||||
getOptions() {
|
||||
return ctx.options
|
||||
},
|
||||
|
||||
...setupDatabaseRPC(ctx),
|
||||
...setupResourceRPC(ctx),
|
||||
|
||||
async reset() {
|
||||
const ws = await ctx.wsServer
|
||||
ws.send('nuxt-mongoose:reset')
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,22 @@
|
||||
import fs from 'fs-extra'
|
||||
import { resolve } from 'pathe'
|
||||
import type { Collection, NuxtDevtoolsServerContext, Resource, ServerFunctions } from '../types'
|
||||
import { generateApiRoute, generateSchemaFile } from '../utils/schematics'
|
||||
import { capitalize, pluralize, singularize } from '../utils/formatting'
|
||||
import { join } from 'pathe'
|
||||
import mongoose from 'mongoose'
|
||||
import type { Collection, DevtoolsServerContext, Resource, ServerFunctions } from '../types'
|
||||
import { capitalize, generateApiRoute, generateSchemaFile, pluralize, singularize } from '../utils'
|
||||
|
||||
export function setupResourceRPC({ nuxt, rpc }: NuxtDevtoolsServerContext): any {
|
||||
const runtimeConfig = nuxt.options.runtimeConfig as any
|
||||
export function setupResourceRPC({ nuxt }: DevtoolsServerContext): any {
|
||||
const config = nuxt.options.runtimeConfig.mongoose
|
||||
|
||||
return {
|
||||
// TODO: maybe separate functions
|
||||
async generateResource(collection: Collection, resources: Resource[]) {
|
||||
const singular = singularize(collection.name).toLowerCase()
|
||||
const plural = pluralize(collection.name).toLowerCase()
|
||||
const dbName = capitalize(singular)
|
||||
|
||||
if (collection.fields) {
|
||||
const schemaPath = resolve(nuxt.options.serverDir, runtimeConfig.mongoose.modelsDir, `${singular}.schema.ts`)
|
||||
const schemaPath = join(config.modelsDir, `${singular}.schema.ts`)
|
||||
if (!fs.existsSync(schemaPath)) {
|
||||
fs.ensureDirSync(resolve(nuxt.options.serverDir, runtimeConfig.mongoose.modelsDir))
|
||||
fs.ensureDirSync(config.modelsDir)
|
||||
fs.writeFileSync(schemaPath, generateSchemaFile(dbName, collection.fields))
|
||||
}
|
||||
|
||||
@ -36,9 +35,9 @@ export function setupResourceRPC({ nuxt, rpc }: NuxtDevtoolsServerContext): any
|
||||
? (routeTypes[route.type] as any)(route.by)
|
||||
: routeTypes[route.type]
|
||||
|
||||
const filePath = resolve(nuxt.options.serverDir, 'api', plural, fileName)
|
||||
const filePath = join(nuxt.options.serverDir, 'api', plural, fileName)
|
||||
if (!fs.existsSync(filePath)) {
|
||||
fs.ensureDirSync(resolve(nuxt.options.serverDir, `api/${plural}`))
|
||||
fs.ensureDirSync(join(nuxt.options.serverDir, `api/${plural}`))
|
||||
const content = generateApiRoute(route.type, { model, by: route.by })
|
||||
fs.writeFileSync(filePath, content)
|
||||
}
|
||||
@ -46,14 +45,13 @@ export function setupResourceRPC({ nuxt, rpc }: NuxtDevtoolsServerContext): any
|
||||
}
|
||||
|
||||
// create collection if not exists
|
||||
const collections = await rpc.functions.listCollections()
|
||||
const collections = await mongoose.connection.db.listCollections().toArray()
|
||||
if (!collections.find((c: any) => c.name === plural))
|
||||
await rpc.functions.createCollection(plural)
|
||||
return await mongoose.connection.db.createCollection(plural)
|
||||
},
|
||||
async resourceSchema(collection: string) {
|
||||
// TODO: use magicast
|
||||
const singular = singularize(collection).toLowerCase()
|
||||
const schemaPath = resolve(nuxt.options.serverDir, runtimeConfig.mongoose.modelsDir, `${singular}.schema.ts`)
|
||||
const schemaPath = join(config.modelsDir, `${singular}.schema.ts`)
|
||||
if (fs.existsSync(schemaPath)) {
|
||||
const content = fs.readFileSync(schemaPath, 'utf-8').match(/schema: \{(.|\n)*\}/g)
|
||||
if (content) {
|
||||
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Due to an upstream bug in Nuxt 3 we need to stub the plugin here, track:https://github.com/nuxt/nuxt/issues/18556
|
||||
* */
|
||||
*/
|
||||
import type { NitroApp } from 'nitropack'
|
||||
import { defineMongooseConnection } from '../services/mongoose'
|
||||
import { defineMongooseConnection } from '../services'
|
||||
|
||||
type NitroAppPlugin = (nitro: NitroApp) => void
|
||||
|
||||
|
||||
@ -1 +1,50 @@
|
||||
export { defineMongooseConnection, defineMongooseModel } from './mongoose'
|
||||
import { logger } from '@nuxt/kit'
|
||||
import mongoose from 'mongoose'
|
||||
import type { ConnectOptions, Model, SchemaDefinition, SchemaOptions } from 'mongoose'
|
||||
|
||||
import { useRuntimeConfig } from '#imports'
|
||||
|
||||
export async function defineMongooseConnection({ uri, options }: { uri?: string; options?: ConnectOptions } = {}): Promise<void> {
|
||||
// TODO: types
|
||||
const config = useRuntimeConfig().mongoose
|
||||
const mongooseUri = uri || config.uri
|
||||
const mongooseOptions = options || config.options
|
||||
|
||||
try {
|
||||
await mongoose.connect(mongooseUri, { ...mongooseOptions })
|
||||
logger.success('Connected to `MongoDB`')
|
||||
}
|
||||
catch (err) {
|
||||
logger.error('Error connecting to `MongoDB`', err)
|
||||
}
|
||||
}
|
||||
|
||||
export function defineMongooseModel<T>(
|
||||
nameOrOptions: string | {
|
||||
name: string
|
||||
schema: SchemaDefinition
|
||||
options?: SchemaOptions
|
||||
hooks?: (schema: mongoose.Schema<T>) => void
|
||||
},
|
||||
schema?: SchemaDefinition,
|
||||
options?: SchemaOptions,
|
||||
hooks?: (schema: mongoose.Schema<T>) => void,
|
||||
): Model<T> {
|
||||
let name: string
|
||||
if (typeof nameOrOptions === 'string') {
|
||||
name = nameOrOptions
|
||||
}
|
||||
else {
|
||||
name = nameOrOptions.name
|
||||
schema = nameOrOptions.schema
|
||||
options = nameOrOptions.options
|
||||
hooks = nameOrOptions.hooks
|
||||
}
|
||||
|
||||
const newSchema = new mongoose.Schema<T>(schema, options as any)
|
||||
|
||||
if (hooks)
|
||||
hooks(newSchema)
|
||||
|
||||
return mongoose.model<T>(name, newSchema)
|
||||
}
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
import type { ConnectOptions, Model, SchemaDefinition, SchemaOptions } from 'mongoose'
|
||||
import mongoose from 'mongoose'
|
||||
import { logger } from '@nuxt/kit'
|
||||
|
||||
import { useRuntimeConfig } from '#imports'
|
||||
|
||||
export async function defineMongooseConnection({ uri, options }: { uri?: string; options?: ConnectOptions } = {}): Promise<void> {
|
||||
const config = useRuntimeConfig().mongoose
|
||||
const mongooseUri = uri || config.uri
|
||||
const mongooseOptions = options || config.options
|
||||
|
||||
try {
|
||||
await mongoose.connect(mongooseUri, { ...mongooseOptions })
|
||||
logger.success('Connected to MongoDB database')
|
||||
}
|
||||
catch (err) {
|
||||
logger.error('Error connecting to MongoDB database', err)
|
||||
}
|
||||
}
|
||||
|
||||
export function defineMongooseModel<T>(
|
||||
nameOrOptions: string | {
|
||||
name: string
|
||||
schema: SchemaDefinition
|
||||
options?: SchemaOptions
|
||||
hooks?: (schema: mongoose.Schema<T>) => void
|
||||
},
|
||||
schema?: SchemaDefinition,
|
||||
options?: SchemaOptions,
|
||||
hooks?: (schema: mongoose.Schema<T>) => void,
|
||||
): Model<T> {
|
||||
let name: string
|
||||
if (typeof nameOrOptions === 'string') {
|
||||
name = nameOrOptions
|
||||
}
|
||||
else {
|
||||
name = nameOrOptions.name
|
||||
schema = nameOrOptions.schema
|
||||
options = nameOrOptions.options
|
||||
hooks = nameOrOptions.hooks
|
||||
}
|
||||
|
||||
const newSchema = new mongoose.Schema<T>(schema, options as any)
|
||||
|
||||
if (hooks)
|
||||
hooks(newSchema)
|
||||
|
||||
return mongoose.model<T>(name, newSchema)
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
import type { WebSocket } from 'ws'
|
||||
import { createBirpcGroup } from 'birpc'
|
||||
import type { ChannelOptions } from 'birpc'
|
||||
|
||||
import { parse, stringify } from 'flatted'
|
||||
import type { Plugin } from 'vite'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import type { ClientFunctions, ModuleOptions, NuxtDevtoolsServerContext, ServerFunctions } from '../types'
|
||||
import { WS_EVENT_NAME } from '../constants'
|
||||
import { setupDatabaseRPC } from './database'
|
||||
import { setupResourceRPC } from './resource'
|
||||
|
||||
export function setupRPC(nuxt: Nuxt, options: ModuleOptions): any {
|
||||
const serverFunctions = {} as ServerFunctions
|
||||
const extendedRpcMap = new Map<string, any>()
|
||||
const rpc = createBirpcGroup<ClientFunctions, ServerFunctions>(
|
||||
serverFunctions,
|
||||
[],
|
||||
{
|
||||
resolver: (name, fn) => {
|
||||
if (fn)
|
||||
return fn
|
||||
|
||||
if (!name.includes(':'))
|
||||
return
|
||||
|
||||
const [namespace, fnName] = name.split(':')
|
||||
return extendedRpcMap.get(namespace)?.[fnName]
|
||||
},
|
||||
onError(error, name) {
|
||||
console.error(`[nuxt-devtools] RPC error on executing "${name}":`, error)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
function refresh(event: keyof ServerFunctions) {
|
||||
rpc.broadcast.refresh.asEvent(event)
|
||||
}
|
||||
|
||||
function extendServerRpc(namespace: string, functions: any): any {
|
||||
extendedRpcMap.set(namespace, functions)
|
||||
|
||||
return {
|
||||
broadcast: new Proxy({}, {
|
||||
get: (_, key) => {
|
||||
if (typeof key !== 'string')
|
||||
return
|
||||
return (rpc.broadcast as any)[`${namespace}:${key}`]
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
const ctx: NuxtDevtoolsServerContext = {
|
||||
nuxt,
|
||||
options,
|
||||
rpc,
|
||||
refresh,
|
||||
extendServerRpc,
|
||||
}
|
||||
|
||||
// @ts-expect-error untyped
|
||||
nuxt.devtools = ctx
|
||||
|
||||
Object.assign(serverFunctions, {
|
||||
...setupDatabaseRPC(ctx),
|
||||
...setupResourceRPC(ctx),
|
||||
} satisfies Partial<ServerFunctions>)
|
||||
|
||||
const wsClients = new Set<WebSocket>()
|
||||
|
||||
const vitePlugin: Plugin = {
|
||||
name: 'nuxt:devtools:rpc',
|
||||
configureServer(server) {
|
||||
server.ws.on('connection', (ws) => {
|
||||
wsClients.add(ws)
|
||||
const channel: ChannelOptions = {
|
||||
post: d => ws.send(JSON.stringify({
|
||||
type: 'custom',
|
||||
event: WS_EVENT_NAME,
|
||||
data: d,
|
||||
})),
|
||||
on: (fn) => {
|
||||
ws.on('message', (e) => {
|
||||
try {
|
||||
const data = JSON.parse(String(e)) || {}
|
||||
if (data.type === 'custom' && data.event === WS_EVENT_NAME) {
|
||||
// console.log(data.data)
|
||||
fn(data.data)
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
})
|
||||
},
|
||||
serialize: stringify,
|
||||
deserialize: parse,
|
||||
}
|
||||
rpc.updateChannels((c) => {
|
||||
c.push(channel)
|
||||
})
|
||||
ws.on('close', () => {
|
||||
wsClients.delete(ws)
|
||||
rpc.updateChannels((c) => {
|
||||
const index = c.indexOf(channel)
|
||||
if (index >= 0)
|
||||
c.splice(index, 1)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
vitePlugin,
|
||||
...ctx,
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,47 @@
|
||||
export * from './rpc'
|
||||
export * from './server-ctx'
|
||||
export * from './module-options'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import type { WebSocketServer } from 'vite'
|
||||
import type { ModuleOptions } from '../module'
|
||||
|
||||
export interface ServerFunctions {
|
||||
getOptions(): ModuleOptions
|
||||
|
||||
// Database - collections
|
||||
readyState(): Promise<any>
|
||||
createCollection(name: string): Promise<any>
|
||||
listCollections(): Promise<any>
|
||||
getCollection(name: string): Promise<any>
|
||||
dropCollection(name: string): Promise<any>
|
||||
|
||||
// Database - documents
|
||||
createDocument(collection: string, data: any): Promise<any>
|
||||
countDocuments(collection: string): Promise<any>
|
||||
listDocuments(collection: string, options: any): Promise<any>
|
||||
getDocument(collection: string, id: string): Promise<any>
|
||||
updateDocument(collection: string, data: any): Promise<any>
|
||||
deleteDocument(collection: string, id: string): Promise<any>
|
||||
|
||||
// Resource - api-routes & models
|
||||
generateResource(collection: Collection, resources: Resource[]): Promise<any>
|
||||
resourceSchema(collection: string): Promise<any>
|
||||
|
||||
reset(): void
|
||||
}
|
||||
|
||||
export interface ClientFunctions {
|
||||
}
|
||||
|
||||
export interface DevtoolsServerContext {
|
||||
nuxt: Nuxt
|
||||
options: ModuleOptions
|
||||
wsServer: Promise<WebSocketServer>
|
||||
}
|
||||
|
||||
export interface Collection {
|
||||
name: string
|
||||
fields?: object[]
|
||||
}
|
||||
|
||||
export interface Resource {
|
||||
type: 'index' | 'create' | 'show' | 'put' | 'delete'
|
||||
by?: string
|
||||
}
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import type { ConnectOptions } from 'mongoose'
|
||||
|
||||
export interface ModuleOptions {
|
||||
uri: string
|
||||
devtools: boolean
|
||||
options?: ConnectOptions
|
||||
modelsDir?: string
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
export interface ServerFunctions {
|
||||
// Database - collections
|
||||
readyState(): Promise<any>
|
||||
createCollection(name: string): Promise<any>
|
||||
listCollections(): Promise<any>
|
||||
getCollection(name: string): Promise<any>
|
||||
dropCollection(name: string): Promise<any>
|
||||
|
||||
// Database - documents
|
||||
createDocument(collection: string, data: any): Promise<any>
|
||||
countDocuments(collection: string): Promise<any>
|
||||
listDocuments(collection: string, options: any): Promise<any>
|
||||
getDocument(collection: string, id: string): Promise<any>
|
||||
updateDocument(collection: string, data: any): Promise<any>
|
||||
deleteDocument(collection: string, id: string): Promise<any>
|
||||
|
||||
// Resource - api-routes & models
|
||||
generateResource(collection: Collection, resources: Resource[]): Promise<any>
|
||||
resourceSchema(collection: string): Promise<any>
|
||||
}
|
||||
|
||||
export interface ClientFunctions {
|
||||
refresh(type: string): void
|
||||
}
|
||||
|
||||
export interface Collection {
|
||||
name: string
|
||||
fields?: object[]
|
||||
}
|
||||
|
||||
export interface Resource {
|
||||
type: 'index' | 'create' | 'show' | 'put' | 'delete'
|
||||
by?: string
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
import type { BirpcGroup } from 'birpc'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import type { ClientFunctions, ServerFunctions } from './rpc'
|
||||
import type { ModuleOptions } from './module-options'
|
||||
|
||||
export interface NuxtDevtoolsServerContext {
|
||||
nuxt: Nuxt
|
||||
options: ModuleOptions
|
||||
|
||||
rpc: BirpcGroup<ClientFunctions, ServerFunctions>
|
||||
|
||||
refresh: (event: keyof ServerFunctions) => void
|
||||
|
||||
extendServerRpc: <ClientFunctions = object, ServerFunctions = object>(name: string, functions: ServerFunctions) => BirpcGroup<ClientFunctions, ServerFunctions>
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
import plrz from 'pluralize'
|
||||
|
||||
export function normalizeToKebabOrSnakeCase(str: string) {
|
||||
const STRING_DASHERIZE_REGEXP = /\s/g
|
||||
const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g
|
||||
return str
|
||||
.replace(STRING_DECAMELIZE_REGEXP, '$1-$2')
|
||||
.toLowerCase()
|
||||
.replace(STRING_DASHERIZE_REGEXP, '-')
|
||||
}
|
||||
|
||||
export function pluralize(str: string) {
|
||||
return plrz.plural(str)
|
||||
}
|
||||
|
||||
export function singularize(str: string) {
|
||||
return plrz.singular(str)
|
||||
}
|
||||
|
||||
export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
@ -1,4 +1,35 @@
|
||||
import { capitalize } from './formatting'
|
||||
import type { WebSocketServer } from 'vite'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
import plrz from 'pluralize'
|
||||
|
||||
export function useViteWebSocket(nuxt: Nuxt) {
|
||||
return new Promise<WebSocketServer>((_resolve) => {
|
||||
nuxt.hooks.hook('vite:serverCreated', (viteServer) => {
|
||||
_resolve(viteServer.ws)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function normalizeToKebabOrSnakeCase(str: string) {
|
||||
const STRING_DASHERIZE_REGEXP = /\s/g
|
||||
const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g
|
||||
return str
|
||||
.replace(STRING_DECAMELIZE_REGEXP, '$1-$2')
|
||||
.toLowerCase()
|
||||
.replace(STRING_DASHERIZE_REGEXP, '-')
|
||||
}
|
||||
|
||||
export function pluralize(str: string) {
|
||||
return plrz.plural(str)
|
||||
}
|
||||
|
||||
export function singularize(str: string) {
|
||||
return plrz.singular(str)
|
||||
}
|
||||
|
||||
export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
export function generateSchemaFile(name: string, fields: any) {
|
||||
name = capitalize(name)
|
||||
Reference in New Issue
Block a user