From 5906b0d129e742e4f9b3b54050555c0808263417 Mon Sep 17 00:00:00 2001 From: jpsc Date: Wed, 14 May 2025 14:59:30 +0200 Subject: [PATCH 1/4] feat(enable): add cmd to enable features --- README.md | 8 +- package.json | 1 + pnpm-lock.yaml | 24 ++++-- src/commands/enable.mjs | 158 ++++++++++++++++++++++++++++++++++++++++ src/index.mjs | 4 +- 5 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 src/commands/enable.mjs diff --git a/README.md b/README.md index bf40162..62c88fc 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ npx nuxthub ## Usage ```bash -USAGE nuxthub init|deploy|link|unlink|open|manage|login|logout|logs|whoami +USAGE nuxthub init|deploy|link|unlink|open|manage|login|logout|logs|whoami|database|ensure|enable COMMANDS @@ -35,7 +35,8 @@ COMMANDS logs Display the logs of a deployment. whoami Shows the username of the currently logged in user. database Manage database migrations. - ensure Ensure the NuxtHub Core module is installed and registered in the project. + ensure Ensure the NuxtHub Core module is installed and registered in the project. + enable Enable a specific NuxtHub feature in your project. Use nuxthub --help for more information about a command. ``` @@ -57,7 +58,7 @@ nuxthub deploy --preview See [how to deploy with a GitHub action](https://hub.nuxt.com/docs/getting-started/deploy#github-action). -https://github.com/user-attachments/assets/9d7d9206-1ee3-4f8f-a29d-8b9dd09b9913 +[https://github.com/user-attachments/assets/9d7d9206-1ee3-4f8f-a29d-8b9dd09b9913](https://github.com/user-attachments/assets/9d7d9206-1ee3-4f8f-a29d-8b9dd09b9913) ## Preview before deploy @@ -68,6 +69,7 @@ nuxthub preview ``` Current limitations: + - The `--remote` flag is not supported - `hubAI()` will ask you connect within the terminal with wrangler - `hubBrowser()` is not supported as not supported by `wrangler pages dev` diff --git a/package.json b/package.json index f90e73c..49d5868 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "jiti": "^2.4.2", "listhen": "^1.9.0", "load-json-file": "^7.0.1", + "magicast": "^0.3.5", "mime": "^4.0.7", "ofetch": "^1.4.1", "open": "^10.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b709372..046a96b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 0.10.1 c12: specifier: ^3.0.3 - version: 3.0.3 + version: 3.0.3(magicast@0.3.5) ci-info: specifier: ^4.2.0 version: 4.2.0 @@ -53,6 +53,9 @@ importers: load-json-file: specifier: ^7.0.1 version: 7.0.1 + magicast: + specifier: ^0.3.5 + version: 0.3.5 mime: specifier: ^4.0.7 version: 4.0.7 @@ -98,7 +101,7 @@ importers: version: 9.25.1(jiti@2.4.2) release-it: specifier: ^19.0.1 - version: 19.0.1 + version: 19.0.1(magicast@0.3.5) packages: @@ -1569,6 +1572,9 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -3033,7 +3039,7 @@ snapshots: dependencies: run-applescript: 7.0.0 - c12@3.0.3: + c12@3.0.3(magicast@0.3.5): dependencies: chokidar: 4.0.3 confbox: 0.2.2 @@ -3047,6 +3053,8 @@ snapshots: perfect-debounce: 1.0.0 pkg-types: 2.1.0 rc9: 2.1.2 + optionalDependencies: + magicast: 0.3.5 callsites@3.1.0: {} @@ -3799,6 +3807,12 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magicast@0.3.5: + dependencies: + '@babel/parser': 7.27.0 + '@babel/types': 7.27.0 + source-map-js: 1.2.1 + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -4147,13 +4161,13 @@ snapshots: dependencies: jsesc: 3.0.2 - release-it@19.0.1: + release-it@19.0.1(magicast@0.3.5): dependencies: '@nodeutils/defaults-deep': 1.1.0 '@octokit/rest': 21.1.1 '@phun-ky/typeof': 1.2.5 async-retry: 1.3.3 - c12: 3.0.3 + c12: 3.0.3(magicast@0.3.5) ci-info: 4.2.0 eta: 3.5.0 git-url-parse: 16.1.0 diff --git a/src/commands/enable.mjs b/src/commands/enable.mjs new file mode 100644 index 0000000..8b32800 --- /dev/null +++ b/src/commands/enable.mjs @@ -0,0 +1,158 @@ +import { consola } from 'consola' +import { colors } from 'consola/utils' +import { defineCommand } from 'citty' +import { getNuxtConfig } from '../utils/index.mjs' +import open from 'open' +import { updateConfig } from 'c12/update' + + +const FEATURE_CONFIG = { + 'ai': { + key: 'ai', + docs: 'https://hub.nuxt.com/docs/features/ai', + }, + 'autorag': { + key: 'ai', + docs: 'https://hub.nuxt.com/docs/features/autorag', + }, + 'blob': { + key: 'blob', + docs: 'https://hub.nuxt.com/docs/features/blob', + }, + 'browser': { + key: 'browser', + docs: 'https://hub.nuxt.com/docs/features/browser', + }, + 'cache': { + key: 'cache', + docs: 'https://hub.nuxt.com/docs/features/cache', + }, + 'database': { + key: 'database', + docs: 'https://hub.nuxt.com/docs/features/database', + }, + 'kv': { + key: 'kv', + docs: 'https://hub.nuxt.com/docs/features/kv', + }, + 'openapi': { + key: 'openapi', + docs: 'https://hub.nuxt.com/docs/features/openapi', + }, + 'realtime': { + key: 'realtime', + docs: 'https://hub.nuxt.com/docs/features/realtime', + }, + 'vectorize': { + key: 'vectorize', + docs: 'https://hub.nuxt.com/docs/features/vectorize#getting-started', + requiresConfig: true + }, +} + +function getFeatureConfig(feature) { + return FEATURE_CONFIG[feature] +} + +function isValidFeature(feature) { + return Object.keys(FEATURE_CONFIG).includes(feature) +} + +export default defineCommand({ + meta: { + name: 'enable', + description: 'Enable a specific NuxtHub feature in your project.', + }, + args: { + feature: { + type: 'positional', + description: 'The NuxtHub feature to enable (ai, autorag, blob, browser, cache, database, kv, openapi, realtime, vectorize)', + required: true, + }, + docs: { + type: 'boolean', + description: 'Open the documentation after enabling the feature.', + default: false + } + }, + async run({ args }) { + const feature = args.feature.toLowerCase() + + if (!isValidFeature(feature)) { + consola.error(`Invalid feature: ${colors.red(feature)}`) + consola.info(`Available features: ${Object.keys(FEATURE_CONFIG).map(f => colors.cyan(f)).join(', ')}`) + return 1 + } + + const featureConfig = getFeatureConfig(feature) + const featureKey = featureConfig.key + const requiresConfig = featureConfig.requiresConfig + + const cwd = process.cwd() + const nuxtConfig = await getNuxtConfig(cwd) + + const hubConfig = nuxtConfig.hub || {} + + if (hubConfig[featureKey] === true) { + consola.info(`NuxtHub ${colors.cyan(featureKey)} feature is already enabled in this project.`) + } else { + + if (requiresConfig) { + consola.warn(`The ${colors.cyan(featureKey)} feature requires additional configuration and cannot be enabled with just a flag.`) + consola.info(`Please refer to the documentation for configuration details: ${colors.underline(featureConfig.docs)}`) + + // managing exit codes + return 1 + } + + try { + const { created } = await updateConfig({ + cwd, + configFile: 'nuxt.config', + + // if the config file doesn't exist, create it + onCreate: () => { + consola.info(`Creating new Nuxt config with ${colors.cyan(featureKey)} feature enabled...`) + return `export default defineNuxtConfig({ + hub: { + ${featureKey}: true + } +})` + }, + + onUpdate: (config) => { + config.hub = config.hub || {} + if (config.hub[featureKey] === true) { + consola.info(`NuxtHub ${colors.cyan(featureKey)} feature is already enabled in this project.`) + return false + } + + config.hub[featureKey] = true + } + }) + + if (created) { + consola.success(`Created new Nuxt config with ${colors.cyan(featureKey)} feature enabled.`) + } else { + consola.success(`NuxtHub ${colors.cyan(featureKey)} feature has been enabled in your project.`) + } + } catch (error) { + consola.error(`Failed to enable ${colors.cyan(featureKey)}: ${error.message}`) + return 1 + } + } + + const docsUrl = featureConfig.docs + + if (!requiresConfig || hubConfig[featureKey] !== true) { + consola.info(`Learn more about the ${colors.cyan(feature)} feature at: ${colors.underline(docsUrl)}`) + } + + if (args.docs) { + consola.info(`Opening documentation at ${colors.cyan(docsUrl)}...`) + open(docsUrl) + } + + return 0 + }, +}) diff --git a/src/index.mjs b/src/index.mjs index 1558324..39b6e82 100755 --- a/src/index.mjs +++ b/src/index.mjs @@ -19,6 +19,7 @@ import open from './commands/open.mjs' import manage from './commands/manage.mjs' import database from './commands/database.mjs' import ensure from './commands/ensure.mjs' +import enable from './commands/enable.mjs' const __dirname = dirname(fileURLToPath(import.meta.url)) const pkg = loadJsonFileSync(resolve(__dirname, '../package.json')) @@ -48,7 +49,8 @@ const main = defineCommand({ logs, whoami, database, - ensure + ensure, + enable }, }) From 03e1b1862b3f7e80e023348f998dcaf0a762bd54 Mon Sep 17 00:00:00 2001 From: jpsc Date: Wed, 14 May 2025 15:29:38 +0200 Subject: [PATCH 2/4] feat(enable): add edge cases for openAPI, vectorize and realtime --- src/commands/enable.mjs | 118 +++++++++++++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 21 deletions(-) diff --git a/src/commands/enable.mjs b/src/commands/enable.mjs index 8b32800..f0475d5 100644 --- a/src/commands/enable.mjs +++ b/src/commands/enable.mjs @@ -36,12 +36,18 @@ const FEATURE_CONFIG = { docs: 'https://hub.nuxt.com/docs/features/kv', }, 'openapi': { - key: 'openapi', + key: null, docs: 'https://hub.nuxt.com/docs/features/openapi', + nitroExperimental: { + openAPI: true + } }, 'realtime': { - key: 'realtime', + key: 'workers', docs: 'https://hub.nuxt.com/docs/features/realtime', + nitroExperimental: { + websocket: true + } }, 'vectorize': { key: 'vectorize', @@ -58,6 +64,74 @@ function isValidFeature(feature) { return Object.keys(FEATURE_CONFIG).includes(feature) } +function generateInitialConfig(featureKey, featureConfig) { + let configContent = `export default defineNuxtConfig({` + + // Add hub config if featureKey exists + if (featureKey) { + configContent += ` + hub: { + ${featureKey}: true + }` + } + + // Add Nitro experimental configs if required + if (featureConfig.nitroExperimental) { + // Add comma if we already have hub config + configContent += featureKey ? `,` : `` + configContent += ` + nitro: { + experimental: {` + + Object.entries(featureConfig.nitroExperimental).forEach(([feature, value], index, array) => { + configContent += ` + ${feature}: ${value}` + // add comma if it's not the last entry + if (index < array.length - 1) { + configContent += ',' + } + }) + + configContent += ` + } + }` + } + + configContent += ` +})` + + return configContent +} + + +function applyAdditionalConfig(config, featureConfig) { + if (featureConfig.nitroExperimental) { + config.nitro = config.nitro || {} + config.nitro.experimental = config.nitro.experimental || {} + + Object.entries(featureConfig.nitroExperimental).forEach(([feature, value]) => { + config.nitro.experimental[feature] = value + }) + } +} + +function isFeatureEnabled(nuxtConfig, featureConfig) { + const featureKey = featureConfig.key + const hubConfig = nuxtConfig.hub || {} + + if (featureKey && hubConfig[featureKey] === true) { + return true + } + + if (!featureKey && featureConfig.nitroExperimental && nuxtConfig.nitro?.experimental) { + return Object.entries(featureConfig.nitroExperimental).every( + ([key, value]) => nuxtConfig.nitro.experimental[key] === value + ) + } + + return false +} + export default defineCommand({ meta: { name: 'enable', @@ -91,14 +165,13 @@ export default defineCommand({ const cwd = process.cwd() const nuxtConfig = await getNuxtConfig(cwd) - const hubConfig = nuxtConfig.hub || {} - - if (hubConfig[featureKey] === true) { - consola.info(`NuxtHub ${colors.cyan(featureKey)} feature is already enabled in this project.`) + // Check if feature is already enabled + if (isFeatureEnabled(nuxtConfig, featureConfig)) { + consola.info(`NuxtHub ${colors.cyan(feature)} feature is already enabled in this project.`) } else { if (requiresConfig) { - consola.warn(`The ${colors.cyan(featureKey)} feature requires additional configuration and cannot be enabled with just a flag.`) + consola.warn(`The ${colors.cyan(feature)} feature requires additional configuration and cannot be enabled with just a flag.`) consola.info(`Please refer to the documentation for configuration details: ${colors.underline(featureConfig.docs)}`) // managing exit codes @@ -112,39 +185,42 @@ export default defineCommand({ // if the config file doesn't exist, create it onCreate: () => { - consola.info(`Creating new Nuxt config with ${colors.cyan(featureKey)} feature enabled...`) - return `export default defineNuxtConfig({ - hub: { - ${featureKey}: true - } -})` + consola.info(`Creating new Nuxt config with ${colors.cyan(feature)} feature enabled...`) + return generateInitialConfig(featureKey, featureConfig) }, onUpdate: (config) => { - config.hub = config.hub || {} - if (config.hub[featureKey] === true) { - consola.info(`NuxtHub ${colors.cyan(featureKey)} feature is already enabled in this project.`) + // Check if feature is already enabled + if (isFeatureEnabled(config, featureConfig)) { + consola.info(`NuxtHub ${colors.cyan(feature)} feature is already enabled in this project.`) return false } - config.hub[featureKey] = true + // Only update hub config if featureKey exists + if (featureKey) { + config.hub = config.hub || {} + config.hub[featureKey] = true + } + + applyAdditionalConfig(config, featureConfig) } }) if (created) { - consola.success(`Created new Nuxt config with ${colors.cyan(featureKey)} feature enabled.`) + consola.success(`Created new Nuxt config with ${colors.cyan(feature)} feature enabled.`) } else { - consola.success(`NuxtHub ${colors.cyan(featureKey)} feature has been enabled in your project.`) + consola.success(`NuxtHub ${colors.cyan(feature)} feature has been enabled in your project.`) } } catch (error) { - consola.error(`Failed to enable ${colors.cyan(featureKey)}: ${error.message}`) + consola.error(`Failed to enable ${colors.cyan(feature)}: ${error.message}`) return 1 } } const docsUrl = featureConfig.docs - if (!requiresConfig || hubConfig[featureKey] !== true) { + // Check if we should show the documentation message + if (!requiresConfig || !isFeatureEnabled(nuxtConfig, featureConfig)) { consola.info(`Learn more about the ${colors.cyan(feature)} feature at: ${colors.underline(docsUrl)}`) } From 2e2fe8f21e4a485ebdd13a09a252b1df9455a7fe Mon Sep 17 00:00:00 2001 From: jpsc Date: Wed, 14 May 2025 15:43:13 +0200 Subject: [PATCH 3/4] feat(enable): remove docs flag --- src/commands/enable.mjs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/commands/enable.mjs b/src/commands/enable.mjs index f0475d5..3728d0c 100644 --- a/src/commands/enable.mjs +++ b/src/commands/enable.mjs @@ -2,7 +2,6 @@ import { consola } from 'consola' import { colors } from 'consola/utils' import { defineCommand } from 'citty' import { getNuxtConfig } from '../utils/index.mjs' -import open from 'open' import { updateConfig } from 'c12/update' @@ -67,7 +66,7 @@ function isValidFeature(feature) { function generateInitialConfig(featureKey, featureConfig) { let configContent = `export default defineNuxtConfig({` - // Add hub config if featureKey exists + // add hub config if featureKey exists if (featureKey) { configContent += ` hub: { @@ -75,9 +74,8 @@ function generateInitialConfig(featureKey, featureConfig) { }` } - // Add Nitro experimental configs if required if (featureConfig.nitroExperimental) { - // Add comma if we already have hub config + // add comma if we already have hub config configContent += featureKey ? `,` : `` configContent += ` nitro: { @@ -142,11 +140,6 @@ export default defineCommand({ type: 'positional', description: 'The NuxtHub feature to enable (ai, autorag, blob, browser, cache, database, kv, openapi, realtime, vectorize)', required: true, - }, - docs: { - type: 'boolean', - description: 'Open the documentation after enabling the feature.', - default: false } }, async run({ args }) { @@ -165,7 +158,7 @@ export default defineCommand({ const cwd = process.cwd() const nuxtConfig = await getNuxtConfig(cwd) - // Check if feature is already enabled + // check if feature is enabled if (isFeatureEnabled(nuxtConfig, featureConfig)) { consola.info(`NuxtHub ${colors.cyan(feature)} feature is already enabled in this project.`) } else { @@ -179,24 +172,33 @@ export default defineCommand({ } try { + let configCreated = false const { created } = await updateConfig({ cwd, configFile: 'nuxt.config', // if the config file doesn't exist, create it onCreate: () => { - consola.info(`Creating new Nuxt config with ${colors.cyan(feature)} feature enabled...`) + configCreated = true return generateInitialConfig(featureKey, featureConfig) }, onUpdate: (config) => { - // Check if feature is already enabled + if (configCreated) { + if (featureKey) { + config.hub = config.hub || {} + config.hub[featureKey] = true + } + + applyAdditionalConfig(config, featureConfig) + return + } + if (isFeatureEnabled(config, featureConfig)) { consola.info(`NuxtHub ${colors.cyan(feature)} feature is already enabled in this project.`) return false } - // Only update hub config if featureKey exists if (featureKey) { config.hub = config.hub || {} config.hub[featureKey] = true @@ -219,16 +221,10 @@ export default defineCommand({ const docsUrl = featureConfig.docs - // Check if we should show the documentation message if (!requiresConfig || !isFeatureEnabled(nuxtConfig, featureConfig)) { consola.info(`Learn more about the ${colors.cyan(feature)} feature at: ${colors.underline(docsUrl)}`) } - if (args.docs) { - consola.info(`Opening documentation at ${colors.cyan(docsUrl)}...`) - open(docsUrl) - } - return 0 }, }) From 5fd3ed25e921f6193514c8b2e937694bb8f1e07d Mon Sep 17 00:00:00 2001 From: jpsc Date: Wed, 14 May 2025 16:13:35 +0200 Subject: [PATCH 4/4] feat(disable): add disable feature --- README.md | 5 ++- src/commands/disable.mjs | 93 ++++++++++++++++++++++++++++++++++++++++ src/commands/enable.mjs | 79 +--------------------------------- src/index.mjs | 2 + src/utils/features.mjs | 74 ++++++++++++++++++++++++++++++++ src/utils/index.mjs | 1 + 6 files changed, 174 insertions(+), 80 deletions(-) create mode 100644 src/commands/disable.mjs create mode 100644 src/utils/features.mjs diff --git a/README.md b/README.md index 62c88fc..9b0ed39 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,13 @@ npx nuxthub ## Usage ```bash -USAGE nuxthub init|deploy|link|unlink|open|manage|login|logout|logs|whoami|database|ensure|enable +USAGE nuxthub init|deploy|disable|link|unlink|open|manage|login|logout|logs|whoami|database|ensure|enable COMMANDS init Initialize a fresh NuxtHUb project, alias of nuxi init -t hub. deploy Deploy your project to NuxtHub. + disable Disable a specific NuxtHub feature in your project. preview Preview your project locally (using wrangler pages dev). link Link a local directory to a NuxtHub project. unlink Unlink a local directory from a NuxtHub project. @@ -34,7 +35,7 @@ COMMANDS logout Logout the current authenticated user. logs Display the logs of a deployment. whoami Shows the username of the currently logged in user. - database Manage database migrations. +database Manage database migrations. ensure Ensure the NuxtHub Core module is installed and registered in the project. enable Enable a specific NuxtHub feature in your project. diff --git a/src/commands/disable.mjs b/src/commands/disable.mjs new file mode 100644 index 0000000..d182444 --- /dev/null +++ b/src/commands/disable.mjs @@ -0,0 +1,93 @@ +import { consola } from 'consola' +import { colors } from 'consola/utils' +import { defineCommand } from 'citty' +import { + getNuxtConfig, + getFeatureConfig, + isValidFeature, + isFeatureEnabled, + FEATURE_CONFIG +} from '../utils/index.mjs' +import { updateConfig } from 'c12/update' + +function removeFeatureConfig(config, featureConfig) { + const featureKey = featureConfig.key + + if (featureKey && config.hub && config.hub[featureKey] === true) { + delete config.hub[featureKey] + + if (Object.keys(config.hub).length === 0) { + delete config.hub + } + } + + if (featureConfig.nitroExperimental && config.nitro?.experimental) { + Object.keys(featureConfig.nitroExperimental).forEach(key => { + if (config.nitro.experimental[key] !== undefined) { + delete config.nitro.experimental[key] + } + }) + + if (Object.keys(config.nitro.experimental).length === 0) { + delete config.nitro.experimental + + if (Object.keys(config.nitro).length === 0) { + delete config.nitro + } + } + } +} + +export default defineCommand({ + meta: { + name: 'disable', + description: 'Disable a specific NuxtHub feature in your project.', + }, + args: { + feature: { + type: 'positional', + description: 'The NuxtHub feature to disable (ai, autorag, blob, browser, cache, database, kv, openapi, realtime, vectorize)', + required: true, + } + }, + async run({ args }) { + const feature = args.feature.toLowerCase() + + if (!isValidFeature(feature)) { + consola.error(`Invalid feature: ${colors.red(feature)}`) + consola.info(`Available features: ${Object.keys(FEATURE_CONFIG).map(f => colors.cyan(f)).join(', ')}`) + return 1 + } + + const featureConfig = getFeatureConfig(feature) + const cwd = process.cwd() + const nuxtConfig = await getNuxtConfig(cwd) + + // check if feature is enabled + if (!isFeatureEnabled(nuxtConfig, featureConfig)) { + consola.info(`NuxtHub ${colors.cyan(feature)} feature is not enabled in this project.`) + return 0 + } + + try { + await updateConfig({ + cwd, + configFile: 'nuxt.config', + onUpdate: (config) => { + if (!isFeatureEnabled(config, featureConfig)) { + consola.info(`NuxtHub ${colors.cyan(feature)} feature is not enabled in this project.`) + return false + } + removeFeatureConfig(config, featureConfig) + } + }) + + consola.success(`NuxtHub ${colors.cyan(feature)} feature has been disabled in your project.`) + } catch (error) { + consola.error(`Failed to disable ${colors.cyan(feature)}: ${error.message}`) + return 1 + } + + return 0 + }, +}) diff --git a/src/commands/enable.mjs b/src/commands/enable.mjs index 3728d0c..12f5b42 100644 --- a/src/commands/enable.mjs +++ b/src/commands/enable.mjs @@ -1,68 +1,9 @@ import { consola } from 'consola' import { colors } from 'consola/utils' import { defineCommand } from 'citty' -import { getNuxtConfig } from '../utils/index.mjs' +import { getNuxtConfig, getFeatureConfig, isValidFeature, isFeatureEnabled, FEATURE_CONFIG } from '../utils/index.mjs' import { updateConfig } from 'c12/update' - -const FEATURE_CONFIG = { - 'ai': { - key: 'ai', - docs: 'https://hub.nuxt.com/docs/features/ai', - }, - 'autorag': { - key: 'ai', - docs: 'https://hub.nuxt.com/docs/features/autorag', - }, - 'blob': { - key: 'blob', - docs: 'https://hub.nuxt.com/docs/features/blob', - }, - 'browser': { - key: 'browser', - docs: 'https://hub.nuxt.com/docs/features/browser', - }, - 'cache': { - key: 'cache', - docs: 'https://hub.nuxt.com/docs/features/cache', - }, - 'database': { - key: 'database', - docs: 'https://hub.nuxt.com/docs/features/database', - }, - 'kv': { - key: 'kv', - docs: 'https://hub.nuxt.com/docs/features/kv', - }, - 'openapi': { - key: null, - docs: 'https://hub.nuxt.com/docs/features/openapi', - nitroExperimental: { - openAPI: true - } - }, - 'realtime': { - key: 'workers', - docs: 'https://hub.nuxt.com/docs/features/realtime', - nitroExperimental: { - websocket: true - } - }, - 'vectorize': { - key: 'vectorize', - docs: 'https://hub.nuxt.com/docs/features/vectorize#getting-started', - requiresConfig: true - }, -} - -function getFeatureConfig(feature) { - return FEATURE_CONFIG[feature] -} - -function isValidFeature(feature) { - return Object.keys(FEATURE_CONFIG).includes(feature) -} - function generateInitialConfig(featureKey, featureConfig) { let configContent = `export default defineNuxtConfig({` @@ -101,7 +42,6 @@ function generateInitialConfig(featureKey, featureConfig) { return configContent } - function applyAdditionalConfig(config, featureConfig) { if (featureConfig.nitroExperimental) { config.nitro = config.nitro || {} @@ -113,23 +53,6 @@ function applyAdditionalConfig(config, featureConfig) { } } -function isFeatureEnabled(nuxtConfig, featureConfig) { - const featureKey = featureConfig.key - const hubConfig = nuxtConfig.hub || {} - - if (featureKey && hubConfig[featureKey] === true) { - return true - } - - if (!featureKey && featureConfig.nitroExperimental && nuxtConfig.nitro?.experimental) { - return Object.entries(featureConfig.nitroExperimental).every( - ([key, value]) => nuxtConfig.nitro.experimental[key] === value - ) - } - - return false -} - export default defineCommand({ meta: { name: 'enable', diff --git a/src/index.mjs b/src/index.mjs index 39b6e82..d708dfa 100755 --- a/src/index.mjs +++ b/src/index.mjs @@ -15,6 +15,7 @@ import logs from './commands/logs.mjs' import whoami from './commands/whoami.mjs' import preview from './commands/preview.mjs' import deploy from './commands/deploy.mjs' +import disable from './commands/disable.mjs' import open from './commands/open.mjs' import manage from './commands/manage.mjs' import database from './commands/database.mjs' @@ -39,6 +40,7 @@ const main = defineCommand({ subCommands: { init, deploy, + disable, preview, link, unlink, diff --git a/src/utils/features.mjs b/src/utils/features.mjs new file mode 100644 index 0000000..4871cb2 --- /dev/null +++ b/src/utils/features.mjs @@ -0,0 +1,74 @@ +export const FEATURE_CONFIG = { + 'ai': { + key: 'ai', + docs: 'https://hub.nuxt.com/docs/features/ai', + }, + 'autorag': { + key: 'ai', + docs: 'https://hub.nuxt.com/docs/features/autorag', + }, + 'blob': { + key: 'blob', + docs: 'https://hub.nuxt.com/docs/features/blob', + }, + 'browser': { + key: 'browser', + docs: 'https://hub.nuxt.com/docs/features/browser', + }, + 'cache': { + key: 'cache', + docs: 'https://hub.nuxt.com/docs/features/cache', + }, + 'database': { + key: 'database', + docs: 'https://hub.nuxt.com/docs/features/database', + }, + 'kv': { + key: 'kv', + docs: 'https://hub.nuxt.com/docs/features/kv', + }, + 'openapi': { + key: null, + docs: 'https://hub.nuxt.com/docs/features/openapi', + nitroExperimental: { + openAPI: true + } + }, + 'realtime': { + key: 'workers', + docs: 'https://hub.nuxt.com/docs/features/realtime', + nitroExperimental: { + websocket: true + } + }, + 'vectorize': { + key: 'vectorize', + docs: 'https://hub.nuxt.com/docs/features/vectorize#getting-started', + requiresConfig: true + }, +} + +export function getFeatureConfig(feature) { + return FEATURE_CONFIG[feature] +} + +export function isValidFeature(feature) { + return Object.keys(FEATURE_CONFIG).includes(feature) +} + +export function isFeatureEnabled(nuxtConfig, featureConfig) { + const featureKey = featureConfig.key + const hubConfig = nuxtConfig.hub || {} + + if (featureKey && hubConfig[featureKey] === true) { + return true + } + + if (!featureKey && featureConfig.nitroExperimental && nuxtConfig.nitro?.experimental) { + return Object.entries(featureConfig.nitroExperimental).every( + ([key, value]) => nuxtConfig.nitro.experimental[key] === value + ) + } + + return false +} diff --git a/src/utils/index.mjs b/src/utils/index.mjs index 6a05801..3d4cd2a 100644 --- a/src/utils/index.mjs +++ b/src/utils/index.mjs @@ -6,3 +6,4 @@ export * from './poll.mjs' export * from './logs.mjs' export * from './wrangler.mjs' export * from './database.mjs' +export * from './features.mjs'