@gzl10/nexus-backend 0.19.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -8709,18 +8709,20 @@ function createSystemController(ctx) {
8709
8709
  /**
8710
8710
  * GET /system/capabilities
8711
8711
  * Public endpoint — no authentication required.
8712
- * Returns backend version and registered plugin codes.
8712
+ * Resolves all registered capabilities (core + plugin-contributed).
8713
8713
  */
8714
- getCapabilities(_req, res) {
8715
- res.set("Cache-Control", "public, max-age=300");
8716
- const manifest = engine.getCoreManifest();
8717
- const plugins = engine.getPlugins();
8718
- const body = {
8719
- version: manifest.version,
8720
- plugins: plugins.map((p) => p.code),
8721
- locales: ctx.locales
8722
- };
8723
- res.json(body);
8714
+ async getCapabilities(_req, res) {
8715
+ try {
8716
+ res.set("Cache-Control", "public, max-age=300");
8717
+ const body = await ctx.capabilities.resolve();
8718
+ res.json(body);
8719
+ } catch (err) {
8720
+ ctx.core.logger.error({ err }, "Failed to resolve capabilities");
8721
+ res.set("Cache-Control", "no-cache");
8722
+ res.status(500).json({
8723
+ error: { code: "INTERNAL_ERROR", message: "Failed to resolve capabilities" }
8724
+ });
8725
+ }
8724
8726
  }
8725
8727
  };
8726
8728
  function toManifestDTO(manifest, req) {
@@ -9293,8 +9295,8 @@ function registerCoreVars(registry2) {
9293
9295
  registry2.register("auth", "core", [
9294
9296
  {
9295
9297
  name: "AUTH_SECRET",
9296
- description: { en: "JWT signing secret. Must be at least 32 characters. Use a cryptographically random string in production", es: "Clave de firma JWT. M\xEDnimo 32 caracteres. Usar una cadena criptogr\xE1ficamente aleatoria en producci\xF3n" },
9297
- required: true,
9298
+ description: { en: "JWT signing secret (optional). If not set, auto-generated and persisted in database. Must be at least 32 characters. Set explicitly for multi-instance deployments", es: "Clave de firma JWT (opcional). Si no se establece, se genera autom\xE1ticamente y se persiste en la base de datos. M\xEDnimo 32 caracteres. Establecer expl\xEDcitamente para despliegues multi-instancia" },
9299
+ required: false,
9298
9300
  sensitive: true
9299
9301
  },
9300
9302
  {
@@ -9811,96 +9813,70 @@ var init_system = __esm({
9811
9813
  }
9812
9814
  });
9813
9815
 
9814
- // src/modules/ui-settings/ui-branding.entity.ts
9815
- import { useTextField as useTextField7, useImageField } from "@gzl10/nexus-sdk/fields";
9816
- var uiBrandingEntity;
9817
- var init_ui_branding_entity = __esm({
9818
- "src/modules/ui-settings/ui-branding.entity.ts"() {
9816
+ // src/modules/ui-settings/ui-style-guide.entity.ts
9817
+ import { useTextField as useTextField7, useImageField, useSelectField as useSelectField6, useColorField, useNumberField as useNumberField4, useSwitchField as useSwitchField2 } from "@gzl10/nexus-sdk/fields";
9818
+ var uiStyleGuideEntity;
9819
+ var init_ui_style_guide_entity = __esm({
9820
+ "src/modules/ui-settings/ui-style-guide.entity.ts"() {
9819
9821
  "use strict";
9820
- uiBrandingEntity = {
9822
+ uiStyleGuideEntity = {
9821
9823
  type: "single",
9822
9824
  realtime: "sync",
9823
- key: "ui_branding",
9824
- label: { en: "Branding", es: "Identidad Corporativa" },
9825
- icon: "mdi:palette-swatch-outline",
9825
+ key: "ui_style_guide",
9826
+ label: { en: "Style Guide", es: "Gu\xEDa de Estilos" },
9827
+ icon: "mdi:palette-outline",
9826
9828
  public: true,
9827
- routePrefix: "/ui-branding",
9829
+ routePrefix: "/ui-style-guide",
9828
9830
  defaults: {
9829
9831
  appName: "Nexus",
9830
9832
  logo: null,
9831
9833
  logoDark: null,
9832
- favicon: null
9834
+ favicon: null,
9835
+ primaryColor: "#3B82F6",
9836
+ font: "space-grotesk",
9837
+ typographyScale: "default",
9838
+ borderRadius: 8,
9839
+ glassEffect: true,
9840
+ theme: "system",
9841
+ loginLayout: "centered"
9833
9842
  },
9834
9843
  fields: {
9835
9844
  appName: useTextField7({
9836
9845
  label: { en: "App Name", es: "Nombre de la App" },
9837
- hint: { en: "Displayed in the header, browser tab and emails", es: "Se muestra en el header, pesta\xF1a del navegador y emails" },
9846
+ hint: { en: "Displayed in header, browser tab and emails", es: "Se muestra en header, pesta\xF1a del navegador y emails" },
9838
9847
  size: 100,
9839
9848
  required: true
9840
9849
  }),
9841
9850
  logo: useImageField({
9842
9851
  label: { en: "Logo (Light Theme)", es: "Logo (Tema Claro)" },
9843
- hint: { en: "Recommended: SVG or PNG with transparent background, max 200px height", es: "Recomendado: SVG o PNG con fondo transparente, m\xE1x 200px de alto" },
9852
+ hint: { en: "SVG or PNG with transparent background, max 200px height", es: "SVG o PNG con fondo transparente, m\xE1x 200px de alto" },
9844
9853
  folder: "branding",
9845
9854
  isPublic: true,
9846
9855
  dedupe: true
9847
9856
  }),
9848
9857
  logoDark: useImageField({
9849
9858
  label: { en: "Logo (Dark Theme)", es: "Logo (Tema Oscuro)" },
9850
- hint: { en: "Optional: Use a lighter version for dark backgrounds", es: "Opcional: Usa una versi\xF3n m\xE1s clara para fondos oscuros" },
9859
+ hint: { en: "Lighter version for dark backgrounds", es: "Versi\xF3n m\xE1s clara para fondos oscuros" },
9851
9860
  folder: "branding",
9852
9861
  isPublic: true,
9853
9862
  dedupe: true
9854
9863
  }),
9855
9864
  favicon: useImageField({
9856
9865
  label: { en: "Favicon", es: "Favicon" },
9857
- hint: { en: "Browser tab icon. Recommended: 32x32 or 64x64 PNG/ICO", es: "Icono de pesta\xF1a del navegador. Recomendado: 32x32 o 64x64 PNG/ICO" },
9866
+ hint: { en: "32x32 or 64x64 PNG/ICO", es: "32x32 o 64x64 PNG/ICO" },
9858
9867
  accept: "image/x-icon,image/png,image/svg+xml",
9859
9868
  maxSize: "256KB",
9860
9869
  folder: "branding",
9861
9870
  isPublic: true,
9862
9871
  dedupe: true
9863
- })
9864
- },
9865
- casl: {
9866
- subject: "UiBranding",
9867
- permissions: {
9868
- ADMIN: { actions: ["read", "update"] }
9869
- }
9870
- }
9871
- };
9872
- }
9873
- });
9874
-
9875
- // src/modules/ui-settings/ui-theme.entity.ts
9876
- import { useSelectField as useSelectField6, useColorField } from "@gzl10/nexus-sdk/fields";
9877
- var uiThemeEntity;
9878
- var init_ui_theme_entity = __esm({
9879
- "src/modules/ui-settings/ui-theme.entity.ts"() {
9880
- "use strict";
9881
- uiThemeEntity = {
9882
- type: "single",
9883
- realtime: "sync",
9884
- key: "ui_theme",
9885
- label: { en: "Theme & Colors", es: "Tema y Colores" },
9886
- icon: "mdi:palette",
9887
- public: true,
9888
- routePrefix: "/ui-theme",
9889
- defaults: {
9890
- // Typography
9891
- font: "space-grotesk",
9892
- // Theme & Colors
9893
- theme: "system",
9894
- primaryColor: "#3B82F6",
9895
- dopamineTheme: "none",
9896
- // Layout
9897
- loginLayout: "centered"
9898
- },
9899
- fields: {
9900
- // === Typography ===
9872
+ }),
9873
+ primaryColor: useColorField({
9874
+ label: { en: "Primary Color", es: "Color Principal" },
9875
+ hint: { en: "Accent color for buttons, links and highlights", es: "Color de acento para botones, enlaces y resaltados" }
9876
+ }),
9901
9877
  font: useSelectField6({
9902
9878
  label: { en: "Font", es: "Fuente" },
9903
- hint: { en: "Primary font for headings and UI elements", es: "Fuente principal para t\xEDtulos y elementos de interfaz" },
9879
+ hint: { en: "Primary font for headings and UI", es: "Fuente principal para t\xEDtulos e interfaz" },
9904
9880
  options: [
9905
9881
  { value: "space-grotesk", label: "Space Grotesk" },
9906
9882
  { value: "inter", label: "Inter" },
@@ -9910,37 +9886,38 @@ var init_ui_theme_entity = __esm({
9910
9886
  { value: "system", label: { en: "System Default", es: "Sistema" } }
9911
9887
  ]
9912
9888
  }),
9913
- // === Theme & Colors ===
9889
+ typographyScale: useSelectField6({
9890
+ label: { en: "Typography Scale", es: "Escala Tipogr\xE1fica" },
9891
+ hint: { en: "Font size scaling (WCAG 1.4.4)", es: "Escala de tama\xF1os de fuente (WCAG 1.4.4)" },
9892
+ options: [
9893
+ { value: "compact", label: { en: "Compact", es: "Compacta" } },
9894
+ { value: "default", label: { en: "Default", es: "Por defecto" } },
9895
+ { value: "relaxed", label: { en: "Relaxed", es: "Relajada" } }
9896
+ ]
9897
+ }),
9898
+ borderRadius: useNumberField4({
9899
+ label: { en: "Border Radius", es: "Radio de Bordes" },
9900
+ hint: { en: "Corner roundness in pixels (0 = sharp, 16 = very round)", es: "Redondeo de esquinas en p\xEDxeles (0 = cuadrado, 16 = muy redondo)" },
9901
+ defaultValue: 8,
9902
+ validation: { min: 0, max: 16 }
9903
+ }),
9904
+ glassEffect: useSwitchField2({
9905
+ label: { en: "Glass Effect", es: "Efecto Glass" },
9906
+ hint: { en: "Glassmorphism blur on cards and modals", es: "Desenfoque glassmorphism en cards y modales" },
9907
+ defaultValue: true
9908
+ }),
9914
9909
  theme: useSelectField6({
9915
9910
  label: { en: "Theme", es: "Tema" },
9916
- hint: { en: "System follows your device preferences", es: "Sistema sigue las preferencias de tu dispositivo" },
9911
+ hint: { en: "System follows device preferences", es: "Sistema sigue las preferencias del dispositivo" },
9917
9912
  options: [
9918
9913
  { value: "light", label: { en: "Light", es: "Claro" } },
9919
9914
  { value: "dark", label: { en: "Dark", es: "Oscuro" } },
9920
9915
  { value: "system", label: { en: "System", es: "Sistema" } }
9921
9916
  ]
9922
9917
  }),
9923
- dopamineTheme: useSelectField6({
9924
- label: { en: "Dopamine Theme", es: "Tema Dopamina" },
9925
- hint: { en: "Vibrant color presets optimized for light and dark modes (2025/2026 trends)", es: "Presets de colores vibrantes optimizados para modo claro y oscuro (tendencias 2025/2026)" },
9926
- options: [
9927
- { value: "none", label: { en: "None (Custom Color)", es: "Ninguno (Color personalizado)" } },
9928
- { value: "electric", label: { en: "Electric (Cobalt Blue)", es: "El\xE9ctrico (Azul Cobalto)" } },
9929
- { value: "sunset", label: { en: "Sunset (Coral Red)", es: "Atardecer (Rojo Coral)" } },
9930
- { value: "ocean", label: { en: "Ocean (Teal)", es: "Oc\xE9ano (Verde Azulado)" } },
9931
- { value: "forest", label: { en: "Forest (Mint)", es: "Bosque (Menta)" } },
9932
- { value: "lavender", label: { en: "Lavender (Violet)", es: "Lavanda (Violeta)" } },
9933
- { value: "cherry", label: { en: "Cherry (Fuchsia)", es: "Cereza (Fucsia)" } },
9934
- { value: "amber", label: { en: "Amber (Golden)", es: "\xC1mbar (Dorado)" } },
9935
- { value: "tangerine", label: { en: "Tangerine (Orange)", es: "Mandarina (Naranja)" } },
9936
- { value: "slate", label: { en: "Slate (Cool Gray)", es: "Pizarra (Gris Fr\xEDo)" } },
9937
- { value: "bronze", label: { en: "Bronze (Earth)", es: "Bronce (Tierra)" } }
9938
- ]
9939
- }),
9940
- // === Login Layout ===
9941
9918
  loginLayout: useSelectField6({
9942
9919
  label: { en: "Login Layout", es: "Dise\xF1o de Login" },
9943
- hint: { en: "Visual layout for authentication pages", es: "Dise\xF1o visual para p\xE1ginas de autenticaci\xF3n" },
9920
+ hint: { en: "Auth page visual layout", es: "Dise\xF1o visual de p\xE1ginas de autenticaci\xF3n" },
9944
9921
  options: [
9945
9922
  { value: "centered", label: { en: "Centered", es: "Centrado" } },
9946
9923
  { value: "split", label: { en: "Split", es: "Dividido" } },
@@ -9948,140 +9925,10 @@ var init_ui_theme_entity = __esm({
9948
9925
  { value: "floating", label: { en: "Floating", es: "Flotante" } },
9949
9926
  { value: "minimal", label: { en: "Minimal", es: "Minimalista" } }
9950
9927
  ]
9951
- }),
9952
- primaryColor: {
9953
- ...useColorField({
9954
- label: { en: "Primary Color", es: "Color Principal" },
9955
- hint: { en: "Custom accent color for buttons, links and highlights", es: "Color de acento personalizado para botones, enlaces y resaltados" }
9956
- }),
9957
- // Hide when a dopamine theme is active (show only if 'none')
9958
- hidden: { field: "dopamineTheme", $ne: "none" }
9959
- }
9960
- },
9961
- casl: {
9962
- subject: "UiTheme",
9963
- permissions: {
9964
- ADMIN: { actions: ["read", "update"] }
9965
- }
9966
- }
9967
- };
9968
- }
9969
- });
9970
-
9971
- // src/modules/ui-settings/ui-effects.entity.ts
9972
- import { useSelectField as useSelectField7, useSwitchField as useSwitchField2 } from "@gzl10/nexus-sdk/fields";
9973
- var uiEffectsEntity;
9974
- var init_ui_effects_entity = __esm({
9975
- "src/modules/ui-settings/ui-effects.entity.ts"() {
9976
- "use strict";
9977
- uiEffectsEntity = {
9978
- type: "single",
9979
- realtime: "sync",
9980
- key: "ui_effects",
9981
- label: { en: "Visual Effects", es: "Efectos Visuales" },
9982
- icon: "mdi:shimmer",
9983
- public: true,
9984
- routePrefix: "/ui-effects",
9985
- defaults: {
9986
- glassIntensity: "medium",
9987
- borderStyle: "rounded",
9988
- enableAnimations: true,
9989
- enableOrganicShapes: false
9990
- },
9991
- fields: {
9992
- glassIntensity: useSelectField7({
9993
- label: { en: "Glass Intensity", es: "Intensidad Glass" },
9994
- hint: { en: "Glassmorphism blur effect on cards and modals", es: "Efecto de desenfoque glassmorphism en cards y modales" },
9995
- options: [
9996
- { value: "none", label: { en: "None", es: "Ninguno" } },
9997
- { value: "low", label: { en: "Low", es: "Baja" } },
9998
- { value: "medium", label: { en: "Medium", es: "Media" } },
9999
- { value: "high", label: { en: "High", es: "Alta" } }
10000
- ]
10001
- }),
10002
- borderStyle: useSelectField7({
10003
- label: { en: "Border Style", es: "Estilo de Bordes" },
10004
- hint: { en: "Corner radius for buttons, cards and inputs", es: "Radio de esquinas para botones, cards e inputs" },
10005
- options: [
10006
- { value: "sharp", label: { en: "Sharp", es: "Cuadrados" } },
10007
- { value: "rounded", label: { en: "Rounded", es: "Redondeados" } },
10008
- { value: "organic", label: { en: "Organic", es: "Org\xE1nicos" } }
10009
- ]
10010
- }),
10011
- enableAnimations: useSwitchField2({
10012
- label: { en: "Enable Animations", es: "Habilitar Animaciones" },
10013
- hint: { en: "Micro-interactions and transitions (hover, focus, page changes)", es: "Micro-interacciones y transiciones (hover, focus, cambios de p\xE1gina)" },
10014
- defaultValue: true,
10015
- meta: { sortable: true }
10016
- }),
10017
- enableOrganicShapes: useSwitchField2({
10018
- label: { en: "Enable Organic Shapes", es: "Habilitar Formas Org\xE1nicas" },
10019
- hint: { en: "Asymmetric border-radius for a more natural, playful look", es: "Border-radius asim\xE9trico para un aspecto m\xE1s natural y divertido" },
10020
- defaultValue: false,
10021
- meta: { sortable: true },
10022
- hidden: { field: "borderStyle", $ne: "organic" }
10023
- })
10024
- },
10025
- casl: {
10026
- subject: "UiEffects",
10027
- permissions: {
10028
- ADMIN: { actions: ["read", "update"] }
10029
- }
10030
- }
10031
- };
10032
- }
10033
- });
10034
-
10035
- // src/modules/ui-settings/ui-accessibility.entity.ts
10036
- import { useSelectField as useSelectField8, useSwitchField as useSwitchField3 } from "@gzl10/nexus-sdk/fields";
10037
- var uiAccessibilityEntity;
10038
- var init_ui_accessibility_entity = __esm({
10039
- "src/modules/ui-settings/ui-accessibility.entity.ts"() {
10040
- "use strict";
10041
- uiAccessibilityEntity = {
10042
- type: "single",
10043
- realtime: "sync",
10044
- key: "ui_accessibility",
10045
- label: { en: "Accessibility", es: "Accesibilidad" },
10046
- icon: "mdi:human",
10047
- public: true,
10048
- routePrefix: "/ui-accessibility",
10049
- defaults: {
10050
- typographyScale: "default",
10051
- reducedMotion: false,
10052
- highContrast: false
10053
- },
10054
- fields: {
10055
- typographyScale: useSelectField8({
10056
- label: { en: "Typography Scale", es: "Escala Tipogr\xE1fica" },
10057
- hint: { en: "Adjusts font sizes for better readability (WCAG 1.4.4)", es: "Ajusta tama\xF1os de fuente para mejor legibilidad (WCAG 1.4.4)" },
10058
- options: [
10059
- { value: "compact", label: { en: "Compact (smaller)", es: "Compacta (m\xE1s peque\xF1a)" } },
10060
- { value: "default", label: { en: "Default", es: "Por defecto" } },
10061
- { value: "relaxed", label: { en: "Relaxed (larger)", es: "Relajada (m\xE1s grande)" } }
10062
- ]
10063
- }),
10064
- reducedMotion: useSwitchField3({
10065
- label: { en: "Reduced Motion", es: "Movimiento Reducido" },
10066
- defaultValue: false,
10067
- meta: { sortable: true },
10068
- hint: {
10069
- en: "Minimizes animations for users sensitive to motion (WCAG 2.1)",
10070
- es: "Minimiza animaciones para usuarios sensibles al movimiento (WCAG 2.1)"
10071
- }
10072
- }),
10073
- highContrast: useSwitchField3({
10074
- label: { en: "High Contrast", es: "Alto Contraste" },
10075
- defaultValue: false,
10076
- meta: { sortable: true },
10077
- hint: {
10078
- en: "Increases text contrast for better readability (WCAG AAA)",
10079
- es: "Aumenta el contraste del texto para mejor legibilidad (WCAG AAA)"
10080
- }
10081
9928
  })
10082
9929
  },
10083
9930
  casl: {
10084
- subject: "UiAccessibility",
9931
+ subject: "UiStyleGuide",
10085
9932
  permissions: {
10086
9933
  ADMIN: { actions: ["read", "update"] }
10087
9934
  }
@@ -10091,44 +9938,62 @@ var init_ui_accessibility_entity = __esm({
10091
9938
  });
10092
9939
 
10093
9940
  // src/modules/ui-settings/index.ts
9941
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
9942
+ import { join as join9 } from "path";
10094
9943
  var uiSettingsModule;
10095
9944
  var init_ui_settings = __esm({
10096
9945
  "src/modules/ui-settings/index.ts"() {
10097
9946
  "use strict";
10098
- init_ui_branding_entity();
10099
- init_ui_theme_entity();
10100
- init_ui_effects_entity();
10101
- init_ui_accessibility_entity();
10102
- init_ui_branding_entity();
10103
- init_ui_theme_entity();
10104
- init_ui_effects_entity();
10105
- init_ui_accessibility_entity();
9947
+ init_ui_style_guide_entity();
9948
+ init_ui_style_guide_entity();
10106
9949
  uiSettingsModule = {
10107
9950
  name: "ui-settings",
10108
- label: { en: "UI Settings", es: "Configuraci\xF3n de UI" },
9951
+ label: { en: "Style Guide", es: "Gu\xEDa de Estilos" },
10109
9952
  icon: "mdi:palette-outline",
10110
9953
  description: {
10111
- en: "User interface configuration: branding, themes, visual effects, and accessibility",
10112
- es: "Configuraci\xF3n de interfaz de usuario: marca, temas, efectos visuales y accesibilidad"
9954
+ en: "Brand identity and visual style configuration",
9955
+ es: "Configuraci\xF3n de identidad de marca y estilo visual"
10113
9956
  },
10114
9957
  type: "core",
10115
9958
  category: "settings",
10116
9959
  dependencies: ["logger"],
10117
- definitions: [
10118
- uiBrandingEntity,
10119
- uiThemeEntity,
10120
- uiEffectsEntity,
10121
- uiAccessibilityEntity
10122
- ],
10123
- routePrefix: "/ui-settings"
9960
+ definitions: [uiStyleGuideEntity],
9961
+ routePrefix: "/ui-settings",
9962
+ /**
9963
+ * Seed style guide from data/seeds/ui-style-guide.json if it exists.
9964
+ * Idempotent: only inserts if no record exists yet.
9965
+ *
9966
+ * Workflow:
9967
+ * 1. Configure style guide in dev via admin UI
9968
+ * 2. Export: GET /api/v1/ui-settings/ui-style-guide → save to data/seeds/ui-style-guide.json
9969
+ * 3. Commit the seed file
9970
+ * 4. On other environments, seed runs automatically on startup
9971
+ */
9972
+ seed: async (ctx) => {
9973
+ const db3 = ctx.db.knex;
9974
+ const existing = await db3("single_records").where("key", "ui_style_guide").first();
9975
+ if (existing) return;
9976
+ const seedPath = join9(process.cwd(), "data", "seeds", "ui-style-guide.json");
9977
+ if (!existsSync6(seedPath)) return;
9978
+ try {
9979
+ const seedData = JSON.parse(readFileSync6(seedPath, "utf-8"));
9980
+ await db3("single_records").insert({
9981
+ key: "ui_style_guide",
9982
+ value: JSON.stringify(seedData)
9983
+ });
9984
+ ctx.core.logger.info("Seeded ui_style_guide from data/seeds/ui-style-guide.json");
9985
+ } catch {
9986
+ ctx.core.logger.warn("Failed to parse data/seeds/ui-style-guide.json, skipping seed");
9987
+ }
9988
+ }
10124
9989
  };
10125
9990
  }
10126
9991
  });
10127
9992
 
10128
9993
  // src/modules/storage/drivers/filesystem.driver.ts
10129
- import { createReadStream, createWriteStream, existsSync as existsSync6, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
9994
+ import { createReadStream, createWriteStream, existsSync as existsSync7, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
10130
9995
  import { readFile, readdir, stat, copyFile, rename, mkdir } from "fs/promises";
10131
- import { join as join9, dirname as dirname6, extname, basename } from "path";
9996
+ import { join as join10, dirname as dirname6, extname, basename } from "path";
10132
9997
  import { createHash } from "crypto";
10133
9998
  var FilesystemDriver;
10134
9999
  var init_filesystem_driver = __esm({
@@ -10142,7 +10007,7 @@ var init_filesystem_driver = __esm({
10142
10007
  this.basePath = config3.basePath;
10143
10008
  this.baseUrl = config3.baseUrl;
10144
10009
  this.generateId = config3.generateId;
10145
- if (!existsSync6(this.basePath)) {
10010
+ if (!existsSync7(this.basePath)) {
10146
10011
  mkdirSync3(this.basePath, { recursive: true });
10147
10012
  }
10148
10013
  }
@@ -10152,9 +10017,9 @@ var init_filesystem_driver = __esm({
10152
10017
  const diskFilename = `${id}${ext}`;
10153
10018
  const folder = options?.folder || "";
10154
10019
  const relativePath = folder ? `${folder}/${diskFilename}` : diskFilename;
10155
- const fullPath = join9(this.basePath, relativePath);
10020
+ const fullPath = join10(this.basePath, relativePath);
10156
10021
  const dir = dirname6(fullPath);
10157
- if (!existsSync6(dir)) {
10022
+ if (!existsSync7(dir)) {
10158
10023
  mkdirSync3(dir, { recursive: true });
10159
10024
  }
10160
10025
  const hash = createHash("sha256").update(buffer).digest("hex");
@@ -10178,25 +10043,25 @@ var init_filesystem_driver = __esm({
10178
10043
  };
10179
10044
  }
10180
10045
  async get(path3) {
10181
- const fullPath = join9(this.basePath, path3);
10182
- if (!existsSync6(fullPath)) {
10046
+ const fullPath = join10(this.basePath, path3);
10047
+ if (!existsSync7(fullPath)) {
10183
10048
  throw new Error(`File not found: ${path3}`);
10184
10049
  }
10185
10050
  return createReadStream(fullPath);
10186
10051
  }
10187
10052
  async getBuffer(path3) {
10188
- const fullPath = join9(this.basePath, path3);
10053
+ const fullPath = join10(this.basePath, path3);
10189
10054
  return readFile(fullPath);
10190
10055
  }
10191
10056
  async delete(path3) {
10192
- const fullPath = join9(this.basePath, path3);
10193
- if (existsSync6(fullPath)) {
10057
+ const fullPath = join10(this.basePath, path3);
10058
+ if (existsSync7(fullPath)) {
10194
10059
  unlinkSync(fullPath);
10195
10060
  }
10196
10061
  }
10197
10062
  async exists(path3) {
10198
- const fullPath = join9(this.basePath, path3);
10199
- return existsSync6(fullPath);
10063
+ const fullPath = join10(this.basePath, path3);
10064
+ return existsSync7(fullPath);
10200
10065
  }
10201
10066
  getUrl(path3) {
10202
10067
  if (!this.baseUrl) return null;
@@ -10206,14 +10071,14 @@ var init_filesystem_driver = __esm({
10206
10071
  // EXTENDED METHODS
10207
10072
  // ============================================================================
10208
10073
  async list(folder) {
10209
- const targetPath = folder ? join9(this.basePath, folder) : this.basePath;
10210
- if (!existsSync6(targetPath)) {
10074
+ const targetPath = folder ? join10(this.basePath, folder) : this.basePath;
10075
+ if (!existsSync7(targetPath)) {
10211
10076
  return [];
10212
10077
  }
10213
10078
  const entries = await readdir(targetPath, { withFileTypes: true });
10214
10079
  const results = [];
10215
10080
  for (const entry of entries) {
10216
- const entryPath = join9(targetPath, entry.name);
10081
+ const entryPath = join10(targetPath, entry.name);
10217
10082
  const relativePath = folder ? `${folder}/${entry.name}` : entry.name;
10218
10083
  const stats = await stat(entryPath);
10219
10084
  results.push({
@@ -10227,10 +10092,10 @@ var init_filesystem_driver = __esm({
10227
10092
  return results;
10228
10093
  }
10229
10094
  async copy(src, dst) {
10230
- const srcPath = join9(this.basePath, src);
10231
- const dstPath = join9(this.basePath, dst);
10095
+ const srcPath = join10(this.basePath, src);
10096
+ const dstPath = join10(this.basePath, dst);
10232
10097
  const dstDir = dirname6(dstPath);
10233
- if (!existsSync6(dstDir)) {
10098
+ if (!existsSync7(dstDir)) {
10234
10099
  await mkdir(dstDir, { recursive: true });
10235
10100
  }
10236
10101
  await copyFile(srcPath, dstPath);
@@ -10253,10 +10118,10 @@ var init_filesystem_driver = __esm({
10253
10118
  };
10254
10119
  }
10255
10120
  async move(src, dst) {
10256
- const srcPath = join9(this.basePath, src);
10257
- const dstPath = join9(this.basePath, dst);
10121
+ const srcPath = join10(this.basePath, src);
10122
+ const dstPath = join10(this.basePath, dst);
10258
10123
  const dstDir = dirname6(dstPath);
10259
- if (!existsSync6(dstDir)) {
10124
+ if (!existsSync7(dstDir)) {
10260
10125
  await mkdir(dstDir, { recursive: true });
10261
10126
  }
10262
10127
  await rename(srcPath, dstPath);
@@ -10279,7 +10144,7 @@ var init_filesystem_driver = __esm({
10279
10144
  };
10280
10145
  }
10281
10146
  async getMetadata(path3) {
10282
- const fullPath = join9(this.basePath, path3);
10147
+ const fullPath = join10(this.basePath, path3);
10283
10148
  const stats = await stat(fullPath);
10284
10149
  return {
10285
10150
  path: path3,
@@ -10293,8 +10158,8 @@ var init_filesystem_driver = __esm({
10293
10158
  throw new Error("Signed URLs are not supported by the filesystem driver");
10294
10159
  }
10295
10160
  async createFolder(path3) {
10296
- const fullPath = join9(this.basePath, path3);
10297
- if (!existsSync6(fullPath)) {
10161
+ const fullPath = join10(this.basePath, path3);
10162
+ if (!existsSync7(fullPath)) {
10298
10163
  await mkdir(fullPath, { recursive: true });
10299
10164
  }
10300
10165
  }
@@ -10525,8 +10390,8 @@ var init_s3_driver = __esm({
10525
10390
  });
10526
10391
 
10527
10392
  // src/modules/storage/storage.config.ts
10528
- import { join as join10, isAbsolute as isAbsolute2 } from "path";
10529
- import { existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
10393
+ import { join as join11, isAbsolute as isAbsolute2 } from "path";
10394
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
10530
10395
  function getDefaultScope(driver) {
10531
10396
  return driver === "s3" ? DEFAULT_S3_SCOPE : DEFAULT_FILESYSTEM_SCOPE;
10532
10397
  }
@@ -10541,7 +10406,7 @@ function resolveStoragePath(path3, projPath) {
10541
10406
  return path3;
10542
10407
  }
10543
10408
  const cleanPath = path3.startsWith("./") ? path3.slice(2) : path3;
10544
- return join10(projPath, "data", cleanPath);
10409
+ return join11(projPath, "data", cleanPath);
10545
10410
  }
10546
10411
  async function getConfigByScope(db3, scope) {
10547
10412
  if (!generateIdFn) {
@@ -10572,7 +10437,7 @@ function buildConfigFromRow(row) {
10572
10437
  if (row.driver === "filesystem") {
10573
10438
  const fsMeta = metadata;
10574
10439
  config3.basePath = resolveStoragePath(fsMeta.basePath || "./storage", projectPath);
10575
- if (!existsSync7(config3.basePath)) {
10440
+ if (!existsSync8(config3.basePath)) {
10576
10441
  mkdirSync4(config3.basePath, { recursive: true });
10577
10442
  }
10578
10443
  } else if (row.driver === "s3") {
@@ -10604,7 +10469,7 @@ function buildConfigFromEnv(driver) {
10604
10469
  if (driver === "filesystem") {
10605
10470
  const rawPath = process.env["STORAGE_PATH"] || "./storage";
10606
10471
  config3.basePath = resolveStoragePath(rawPath, projectPath);
10607
- if (!existsSync7(config3.basePath)) {
10472
+ if (!existsSync8(config3.basePath)) {
10608
10473
  mkdirSync4(config3.basePath, { recursive: true });
10609
10474
  }
10610
10475
  } else if (driver === "s3") {
@@ -11043,7 +10908,7 @@ var init_storage_service = __esm({
11043
10908
  });
11044
10909
 
11045
10910
  // src/modules/storage/storage.entity.ts
11046
- import { useIdField as useIdField3, useTextField as useTextField8, useSelectField as useSelectField9, useUrlField, useNumberField as useNumberField4, useCheckboxField as useCheckboxField3, useJsonField as useJsonField2, useMetadataField, usePublicField } from "@gzl10/nexus-sdk/fields";
10911
+ import { useIdField as useIdField3, useTextField as useTextField8, useSelectField as useSelectField7, useUrlField, useNumberField as useNumberField5, useCheckboxField as useCheckboxField3, useJsonField as useJsonField2, useMetadataField, usePublicField } from "@gzl10/nexus-sdk/fields";
11047
10912
  var DEFAULT_MAX_SIZE2, storageConfigEntity, storageFilesEntity;
11048
10913
  var init_storage_entity = __esm({
11049
10914
  "src/modules/storage/storage.entity.ts"() {
@@ -11078,7 +10943,7 @@ var init_storage_entity = __esm({
11078
10943
  hint: { en: "Unique identifier (e.g. default_filesystem, default_s3)", es: "Identificador \xFAnico (ej: default_filesystem, default_s3)" }
11079
10944
  }),
11080
10945
  driver: {
11081
- ...useSelectField9({
10946
+ ...useSelectField7({
11082
10947
  label: { en: "Driver", es: "Controlador" },
11083
10948
  required: true,
11084
10949
  hint: { en: "Storage backend", es: "Backend de almacenamiento" },
@@ -11095,7 +10960,7 @@ var init_storage_entity = __esm({
11095
10960
  size: 500,
11096
10961
  nullable: true
11097
10962
  }),
11098
- max_file_size: useNumberField4({
10963
+ max_file_size: useNumberField5({
11099
10964
  label: { en: "Max File Size (bytes)", es: "Tama\xF1o m\xE1ximo de archivo (bytes)" },
11100
10965
  hint: { en: "Maximum size in bytes (default: 10MB = 10485760)", es: "Tama\xF1o m\xE1ximo en bytes (default: 10MB = 10485760)" },
11101
10966
  nullable: false,
@@ -11288,7 +11153,7 @@ var init_storage_entity = __esm({
11288
11153
  index: true,
11289
11154
  meta: { sortable: true, searchable: true }
11290
11155
  }),
11291
- size: useNumberField4({
11156
+ size: useNumberField5({
11292
11157
  label: { en: "Size", es: "Tama\xF1o" },
11293
11158
  required: true,
11294
11159
  nullable: false,
@@ -11830,7 +11695,7 @@ var init_storage = __esm({
11830
11695
  });
11831
11696
 
11832
11697
  // src/modules/users/users.entity.ts
11833
- import { useIdField as useIdField4, useSelectField as useSelectField10, useEmailField, usePasswordField, useTextField as useTextField9, useDatetimeField as useDatetimeField3, useCheckboxField as useCheckboxField4, useImageField as useImageField2, useNameField as useNameField2, useMetadataField as useMetadataField2, useDescriptionField as useDescriptionField2 } from "@gzl10/nexus-sdk/fields";
11698
+ import { useIdField as useIdField4, useSelectField as useSelectField8, useEmailField, usePasswordField, useTextField as useTextField9, useDatetimeField as useDatetimeField3, useCheckboxField as useCheckboxField4, useImageField as useImageField2, useNameField as useNameField2, useMetadataField as useMetadataField2, useDescriptionField as useDescriptionField2 } from "@gzl10/nexus-sdk/fields";
11834
11699
  import { z as z3 } from "zod";
11835
11700
  var userEntity, roleEntity, userRoleEntity;
11836
11701
  var init_users_entity = __esm({
@@ -11904,7 +11769,7 @@ var init_users_entity = __esm({
11904
11769
  label: { en: "Marketing Opt-in", es: "Aceptar marketing" },
11905
11770
  meta: { exportable: true, showInForm: false, showInDisplay: false }
11906
11771
  }),
11907
- locale: useSelectField10({
11772
+ locale: useSelectField8({
11908
11773
  label: { en: "Language", es: "Idioma" },
11909
11774
  options: [
11910
11775
  { value: "es", label: { en: "Spanish", es: "Espa\xF1ol" } },
@@ -11914,13 +11779,13 @@ var init_users_entity = __esm({
11914
11779
  meta: { sortable: true },
11915
11780
  defaultValue: "en"
11916
11781
  }),
11917
- timezone: useSelectField10({
11782
+ timezone: useSelectField8({
11918
11783
  label: { en: "Timezone", es: "Zona horaria" },
11919
11784
  master: "timezones",
11920
11785
  meta: { sortable: true },
11921
11786
  defaultValue: "timezones:Europe/Madrid"
11922
11787
  }),
11923
- type: useSelectField10({
11788
+ type: useSelectField8({
11924
11789
  label: { en: "Type", es: "Tipo" },
11925
11790
  defaultValue: "human",
11926
11791
  options: [
@@ -12089,7 +11954,7 @@ var init_users_entity = __esm({
12089
11954
  expose: false,
12090
11955
  fields: {
12091
11956
  id: useIdField4(),
12092
- user_id: useSelectField10({
11957
+ user_id: useSelectField8({
12093
11958
  label: { en: "User", es: "Usuario" },
12094
11959
  required: true,
12095
11960
  table: "users",
@@ -12100,7 +11965,7 @@ var init_users_entity = __esm({
12100
11965
  labelField: "name",
12101
11966
  meta: { searchable: true }
12102
11967
  }),
12103
- role_id: useSelectField10({
11968
+ role_id: useSelectField8({
12104
11969
  label: { en: "Role", es: "Rol" },
12105
11970
  required: true,
12106
11971
  table: "roles",
@@ -13044,7 +12909,7 @@ var init_users = __esm({
13044
12909
  });
13045
12910
 
13046
12911
  // src/modules/auth/auth.entity.ts
13047
- import { useIdField as useIdField5, useTextField as useTextField10, useSelectField as useSelectField11, useDatetimeField as useDatetimeField4, useEmailField as useEmailField2, useMetadataField as useMetadataField3, useExpiresAtField } from "@gzl10/nexus-sdk/fields";
12912
+ import { useIdField as useIdField5, useTextField as useTextField10, useSelectField as useSelectField9, useDatetimeField as useDatetimeField4, useEmailField as useEmailField2, useMetadataField as useMetadataField3, useExpiresAtField } from "@gzl10/nexus-sdk/fields";
13048
12913
  var refreshTokenEntity, authIdentitiesEntity;
13049
12914
  var init_auth_entity = __esm({
13050
12915
  "src/modules/auth/auth.entity.ts"() {
@@ -13125,7 +12990,7 @@ var init_auth_entity = __esm({
13125
12990
  order: 5,
13126
12991
  fields: {
13127
12992
  id: useIdField5(),
13128
- user_id: useSelectField11({
12993
+ user_id: useSelectField9({
13129
12994
  label: { en: "User", es: "Usuario" },
13130
12995
  table: "users",
13131
12996
  column: "id",
@@ -13209,6 +13074,28 @@ var init_auth_routes = __esm({
13209
13074
  }
13210
13075
  });
13211
13076
 
13077
+ // src/core/crypto/secret-resolver.ts
13078
+ import { randomBytes } from "crypto";
13079
+ function _resetSecretResolver() {
13080
+ _secret = null;
13081
+ _db = null;
13082
+ }
13083
+ function getAuthSecret() {
13084
+ if (_secret) return _secret;
13085
+ const envSecret = process.env["AUTH_SECRET"];
13086
+ if (envSecret) return envSecret;
13087
+ throw new Error("AUTH_SECRET not initialized. Call initAuthSecret() during startup.");
13088
+ }
13089
+ var _secret, _db;
13090
+ var init_secret_resolver = __esm({
13091
+ "src/core/crypto/secret-resolver.ts"() {
13092
+ "use strict";
13093
+ init_database();
13094
+ _secret = null;
13095
+ _db = null;
13096
+ }
13097
+ });
13098
+
13212
13099
  // src/modules/auth/auth.config.ts
13213
13100
  import { z as z5 } from "zod";
13214
13101
  function configError(module, errors) {
@@ -13225,12 +13112,6 @@ function parseAuthEnv() {
13225
13112
  if (!result.success) {
13226
13113
  const errors = result.error.issues.map((issue) => {
13227
13114
  const path3 = issue.path.join(".");
13228
- if (path3 === "AUTH_SECRET" && issue.code === "invalid_type") {
13229
- return "AUTH_SECRET is required. Set it in your .env file or environment.";
13230
- }
13231
- if (path3 === "AUTH_SECRET" && issue.code === "too_small") {
13232
- return `AUTH_SECRET must be at least 32 characters (current: ${String(process.env["AUTH_SECRET"]).length})`;
13233
- }
13234
13115
  return `${path3}: ${issue.message}`;
13235
13116
  });
13236
13117
  configError("auth", errors);
@@ -13249,7 +13130,7 @@ function getAuthEnv() {
13249
13130
  function getAuthConfig() {
13250
13131
  const authEnv = getAuthEnv();
13251
13132
  return {
13252
- secret: authEnv.AUTH_SECRET,
13133
+ secret: getAuthSecret(),
13253
13134
  accessExpires: authEnv.AUTH_ACCESS_EXPIRES,
13254
13135
  refreshExpires: authEnv.AUTH_REFRESH_EXPIRES,
13255
13136
  rateLimitMax: authEnv.AUTH_RATE_LIMIT_MAX,
@@ -13266,8 +13147,8 @@ var authEnvSchema, _authEnv;
13266
13147
  var init_auth_config = __esm({
13267
13148
  "src/modules/auth/auth.config.ts"() {
13268
13149
  "use strict";
13150
+ init_secret_resolver();
13269
13151
  authEnvSchema = z5.object({
13270
- AUTH_SECRET: z5.string().min(32, "AUTH_SECRET must be at least 32 characters"),
13271
13152
  AUTH_ACCESS_EXPIRES: z5.string().default("15m"),
13272
13153
  AUTH_REFRESH_EXPIRES: z5.string().default("7d"),
13273
13154
  // Rate limiting (default: 5 requests per 15 minutes)
@@ -13441,7 +13322,7 @@ var init_auth_middleware = __esm({
13441
13322
  });
13442
13323
 
13443
13324
  // src/modules/auth/auth.pat.entity.ts
13444
- import { useIdField as useIdField6, useTextField as useTextField11, useSelectField as useSelectField12, useDatetimeField as useDatetimeField5, useExpiresAtField as useExpiresAtField2 } from "@gzl10/nexus-sdk/fields";
13325
+ import { useIdField as useIdField6, useTextField as useTextField11, useSelectField as useSelectField10, useDatetimeField as useDatetimeField5, useExpiresAtField as useExpiresAtField2 } from "@gzl10/nexus-sdk/fields";
13445
13326
  var personalTokenEntity;
13446
13327
  var init_auth_pat_entity = __esm({
13447
13328
  "src/modules/auth/auth.pat.entity.ts"() {
@@ -13458,7 +13339,7 @@ var init_auth_pat_entity = __esm({
13458
13339
  routePrefix: "/personal-tokens",
13459
13340
  fields: {
13460
13341
  id: useIdField6(),
13461
- user_id: useSelectField12({
13342
+ user_id: useSelectField10({
13462
13343
  label: { en: "User", es: "Usuario" },
13463
13344
  table: "users",
13464
13345
  column: "id",
@@ -13493,7 +13374,7 @@ var init_auth_pat_entity = __esm({
13493
13374
  unique: true,
13494
13375
  meta: { exportable: false }
13495
13376
  }),
13496
- scope: useSelectField12({
13377
+ scope: useSelectField10({
13497
13378
  label: { en: "Permission", es: "Permiso" },
13498
13379
  required: true,
13499
13380
  options: [
@@ -13525,42 +13406,6 @@ var init_auth_pat_entity = __esm({
13525
13406
  }
13526
13407
  });
13527
13408
 
13528
- // src/modules/auth/actions/providers.action.ts
13529
- var providersAction;
13530
- var init_providers_action = __esm({
13531
- "src/modules/auth/actions/providers.action.ts"() {
13532
- "use strict";
13533
- init_auth_config();
13534
- providersAction = {
13535
- key: "providers",
13536
- label: { en: "Get Auth Providers", es: "Obtener proveedores de autenticaci\xF3n" },
13537
- icon: "mdi:account-key",
13538
- scope: "module",
13539
- hidden: true,
13540
- method: "GET",
13541
- skipAuth: true,
13542
- handler: async (ctx) => {
13543
- const providerServices = ctx.services.getBySuffix(".provider");
13544
- const results = await Promise.all(
13545
- providerServices.map(async ({ service }) => {
13546
- try {
13547
- return await service.getInfo();
13548
- } catch {
13549
- return null;
13550
- }
13551
- })
13552
- );
13553
- const providers = results.filter((info) => info !== null);
13554
- const config3 = getAuthConfig();
13555
- return {
13556
- providers,
13557
- registrationEnabled: !config3.disableRegistration
13558
- };
13559
- }
13560
- };
13561
- }
13562
- });
13563
-
13564
13409
  // src/modules/auth/actions/helpers.ts
13565
13410
  function getCookieOptions(req) {
13566
13411
  const config3 = getAuthConfig();
@@ -14117,7 +13962,6 @@ var authActions;
14117
13962
  var init_actions2 = __esm({
14118
13963
  "src/modules/auth/actions/index.ts"() {
14119
13964
  "use strict";
14120
- init_providers_action();
14121
13965
  init_login_action();
14122
13966
  init_register_action();
14123
13967
  init_forgot_password_action();
@@ -14133,7 +13977,6 @@ var init_actions2 = __esm({
14133
13977
  init_list_tokens_action();
14134
13978
  init_revoke_token_action();
14135
13979
  init_impersonate_action();
14136
- init_providers_action();
14137
13980
  init_login_action();
14138
13981
  init_register_action();
14139
13982
  init_forgot_password_action();
@@ -14149,7 +13992,6 @@ var init_actions2 = __esm({
14149
13992
  init_list_tokens_action();
14150
13993
  init_revoke_token_action();
14151
13994
  authActions = [
14152
- providersAction,
14153
13995
  loginAction,
14154
13996
  registerAction,
14155
13997
  forgotPasswordAction,
@@ -14368,7 +14210,7 @@ var init_otp_manager = __esm({
14368
14210
  });
14369
14211
 
14370
14212
  // src/modules/auth/auth.service.ts
14371
- import { createHash as createHash4, randomBytes } from "crypto";
14213
+ import { createHash as createHash4, randomBytes as randomBytes2 } from "crypto";
14372
14214
  function createAuthService(ctx) {
14373
14215
  const { errors, abilities, crypto: crypto3 } = ctx.core;
14374
14216
  const { generateId: generateId2 } = ctx.core;
@@ -14785,7 +14627,7 @@ function createAuthService(ctx) {
14785
14627
  },
14786
14628
  // === Personal Access Tokens ===
14787
14629
  async createPersonalToken(userId, input, requestInfo) {
14788
- const rawToken = "nxs_" + randomBytes(32).toString("hex");
14630
+ const rawToken = "nxs_" + randomBytes2(32).toString("hex");
14789
14631
  const tokenHash = createHash4("sha256").update(rawToken).digest("hex");
14790
14632
  const tokenPrefix = "nxs_..." + rawToken.slice(-6);
14791
14633
  const id = generateId2();
@@ -15121,8 +14963,8 @@ var init_mail_config = __esm({
15121
14963
 
15122
14964
  // src/modules/mail/mail.service.ts
15123
14965
  import nodemailer from "nodemailer";
15124
- import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
15125
- import { join as join11 } from "path";
14966
+ import { readFileSync as readFileSync7, existsSync as existsSync9 } from "fs";
14967
+ import { join as join12 } from "path";
15126
14968
  function getMailService() {
15127
14969
  if (!mailServiceInstance) {
15128
14970
  throw new Error("MailService not initialized. Call initMailService() first.");
@@ -15139,8 +14981,8 @@ var init_mail_service = __esm({
15139
14981
  "src/modules/mail/mail.service.ts"() {
15140
14982
  "use strict";
15141
14983
  init_mail_config();
15142
- TEMPLATE_REL_PATH = join11("public", "mail", "base.html");
15143
- LOGO_REL_PATH = join11("public", "nexus", "nexus-light-512.png");
14984
+ TEMPLATE_REL_PATH = join12("public", "mail", "base.html");
14985
+ LOGO_REL_PATH = join12("public", "nexus", "nexus-light-512.png");
15144
14986
  mailServiceInstance = null;
15145
14987
  MailService = class {
15146
14988
  transporter;
@@ -15154,10 +14996,10 @@ var init_mail_service = __esm({
15154
14996
  this.logger = logger3.child({ service: "mail" });
15155
14997
  this.loggerService = loggerService;
15156
14998
  const libPath = options?.libPath ?? process.cwd();
15157
- this.template = readFileSync6(join11(libPath, TEMPLATE_REL_PATH), "utf-8");
15158
- const logoPath = join11(libPath, LOGO_REL_PATH);
15159
- if (existsSync8(logoPath)) {
15160
- const logoBase64 = readFileSync6(logoPath).toString("base64");
14999
+ this.template = readFileSync7(join12(libPath, TEMPLATE_REL_PATH), "utf-8");
15000
+ const logoPath = join12(libPath, LOGO_REL_PATH);
15001
+ if (existsSync9(logoPath)) {
15002
+ const logoBase64 = readFileSync7(logoPath).toString("base64");
15161
15003
  this.defaultLogoUrl = `data:image/png;base64,${logoBase64}`;
15162
15004
  } else {
15163
15005
  this.defaultLogoUrl = "";
@@ -15249,7 +15091,7 @@ var init_mail_service = __esm({
15249
15091
  });
15250
15092
 
15251
15093
  // src/modules/mail/mail.entity.ts
15252
- import { useIdField as useIdField7, useTextField as useTextField12, useSelectField as useSelectField13, useNumberField as useNumberField5, useSwitchField as useSwitchField4, useEmailField as useEmailField3, usePasswordField as usePasswordField2, useTextareaField as useTextareaField3, useTagsField as useTagsField2, useDatetimeField as useDatetimeField6 } from "@gzl10/nexus-sdk/fields";
15094
+ import { useIdField as useIdField7, useTextField as useTextField12, useSelectField as useSelectField11, useNumberField as useNumberField6, useSwitchField as useSwitchField3, useEmailField as useEmailField3, usePasswordField as usePasswordField2, useTextareaField as useTextareaField3, useTagsField as useTagsField2, useDatetimeField as useDatetimeField6 } from "@gzl10/nexus-sdk/fields";
15253
15095
  import nodemailer2 from "nodemailer";
15254
15096
  async function getMailConfigFromDB(ctx) {
15255
15097
  const configService = ctx.services["config"];
@@ -15318,12 +15160,12 @@ var init_mail_entity = __esm({
15318
15160
  nullable: false,
15319
15161
  hint: { en: "Default: SMTP_HOST env var", es: "Por defecto: variable SMTP_HOST" }
15320
15162
  }),
15321
- port: useNumberField5({
15163
+ port: useNumberField6({
15322
15164
  label: { en: "Port", es: "Puerto" },
15323
15165
  nullable: false,
15324
15166
  hint: { en: "Default: SMTP_PORT env var", es: "Por defecto: variable SMTP_PORT" }
15325
15167
  }),
15326
- secure: useSwitchField4({
15168
+ secure: useSwitchField3({
15327
15169
  label: { en: "TLS/SSL", es: "TLS/SSL" },
15328
15170
  hint: { en: "Default: SMTP_SECURE env var", es: "Por defecto: variable SMTP_SECURE" }
15329
15171
  }),
@@ -15526,7 +15368,7 @@ var init_mail_entity = __esm({
15526
15368
  meta: { searchable: true, sortable: true }
15527
15369
  }),
15528
15370
  status: {
15529
- ...useSelectField13({
15371
+ ...useSelectField11({
15530
15372
  label: { en: "Status", es: "Estado" },
15531
15373
  options: [
15532
15374
  { value: "pending", label: { en: "Pending", es: "Pendiente" } },
@@ -15550,7 +15392,7 @@ var init_mail_entity = __esm({
15550
15392
  label: { en: "Error", es: "Error" },
15551
15393
  nullable: true
15552
15394
  }),
15553
- sent_by: useSelectField13({
15395
+ sent_by: useSelectField11({
15554
15396
  label: { en: "Sent by", es: "Enviado por" },
15555
15397
  table: "users",
15556
15398
  column: "id",
@@ -16176,7 +16018,7 @@ var init_toggle_plugin_action = __esm({
16176
16018
  });
16177
16019
 
16178
16020
  // src/modules/plugins/plugins.entity.ts
16179
- import { useTextField as useTextField13, useSelectField as useSelectField14, useCheckboxField as useCheckboxField5 } from "@gzl10/nexus-sdk/fields";
16021
+ import { useTextField as useTextField13, useSelectField as useSelectField12, useCheckboxField as useCheckboxField5 } from "@gzl10/nexus-sdk/fields";
16180
16022
  import { OFFICIAL_PLUGINS } from "@gzl10/nexus-sdk";
16181
16023
  var allowPluginManagement, pluginsEntity;
16182
16024
  var init_plugins_entity = __esm({
@@ -16218,7 +16060,7 @@ var init_plugins_entity = __esm({
16218
16060
  size: 20,
16219
16061
  nullable: false
16220
16062
  }),
16221
- category: useSelectField14({
16063
+ category: useSelectField12({
16222
16064
  label: { en: "Category", es: "Categor\xEDa" },
16223
16065
  options: [
16224
16066
  { value: "content", label: { en: "Content", es: "Contenido" } },
@@ -16297,7 +16139,7 @@ var init_plugins_entity = __esm({
16297
16139
 
16298
16140
  // src/modules/plugins/plugins.routes.ts
16299
16141
  import { Router } from "express";
16300
- import { existsSync as existsSync9 } from "fs";
16142
+ import { existsSync as existsSync10 } from "fs";
16301
16143
  function createPluginRoutes(ctx) {
16302
16144
  const router = Router();
16303
16145
  let imageMap = null;
@@ -16305,7 +16147,7 @@ function createPluginRoutes(ctx) {
16305
16147
  if (!imageMap) {
16306
16148
  const discovered = await ctx.core.plugins.discover();
16307
16149
  imageMap = new Map(
16308
- discovered.filter((p) => p.image && existsSync9(p.image)).map((p) => [p.code, p.image])
16150
+ discovered.filter((p) => p.image && existsSync10(p.image)).map((p) => [p.code, p.image])
16309
16151
  );
16310
16152
  }
16311
16153
  return imageMap;
@@ -16360,7 +16202,7 @@ var init_plugins = __esm({
16360
16202
  import {
16361
16203
  useIdField as useIdField8,
16362
16204
  useTextField as useTextField14,
16363
- useSelectField as useSelectField15,
16205
+ useSelectField as useSelectField13,
16364
16206
  useTextareaField as useTextareaField4,
16365
16207
  useJsonField as useJsonField3,
16366
16208
  useDatetimeField as useDatetimeField7,
@@ -16402,7 +16244,7 @@ var init_audit_entity = __esm({
16402
16244
  }),
16403
16245
  validation: { min: 1, max: 100 }
16404
16246
  },
16405
- actor_id: useSelectField15({
16247
+ actor_id: useSelectField13({
16406
16248
  label: { en: "Actor", es: "Actor" },
16407
16249
  table: "users",
16408
16250
  column: "id",
@@ -16679,6 +16521,7 @@ import jwt3 from "jsonwebtoken";
16679
16521
  var init_jwt = __esm({
16680
16522
  "src/core/jwt/index.ts"() {
16681
16523
  "use strict";
16524
+ init_secret_resolver();
16682
16525
  }
16683
16526
  });
16684
16527
 
@@ -17090,6 +16933,7 @@ var init_socket = __esm({
17090
16933
  "use strict";
17091
16934
  init_emitter();
17092
16935
  init_logger();
16936
+ init_secret_resolver();
17093
16937
  io = null;
17094
16938
  userSockets = /* @__PURE__ */ new Map();
17095
16939
  socketUsers = /* @__PURE__ */ new Map();
@@ -17283,8 +17127,8 @@ var init_port_check = __esm({
17283
17127
  });
17284
17128
 
17285
17129
  // src/db/seed-runner.ts
17286
- import { existsSync as existsSync10 } from "fs";
17287
- import { join as join12 } from "path";
17130
+ import { existsSync as existsSync11 } from "fs";
17131
+ import { join as join13 } from "path";
17288
17132
  import { pathToFileURL as pathToFileURL2 } from "url";
17289
17133
  var init_seed_runner = __esm({
17290
17134
  "src/db/seed-runner.ts"() {
@@ -18309,7 +18153,7 @@ var init_migration_helpers = __esm({
18309
18153
  // src/db/migration-generator.ts
18310
18154
  import path2 from "path";
18311
18155
  import fs2 from "fs/promises";
18312
- import { readFileSync as readFileSync7, mkdirSync as mkdirSync5, realpathSync } from "fs";
18156
+ import { readFileSync as readFileSync8, mkdirSync as mkdirSync5, realpathSync } from "fs";
18313
18157
  function getColumnIndexBytes(field) {
18314
18158
  if (!field?.db) return 255 * MYSQL_BYTES_PER_CHAR;
18315
18159
  const size = field.db.size ?? 255;
@@ -18401,7 +18245,7 @@ function resolvePrefix(scope) {
18401
18245
  function detectDefaultScope() {
18402
18246
  try {
18403
18247
  const pkgPath = path2.join(getProjectPath(), "package.json");
18404
- const pkg3 = JSON.parse(readFileSync7(pkgPath, "utf-8"));
18248
+ const pkg3 = JSON.parse(readFileSync8(pkgPath, "utf-8"));
18405
18249
  const pkgName = pkg3?.name;
18406
18250
  if (pkgName === "@gzl10/nexus-backend") {
18407
18251
  return "core";
@@ -19190,7 +19034,7 @@ var init_db = __esm({
19190
19034
  // src/core/tunnel.ts
19191
19035
  import { spawn, execSync } from "child_process";
19192
19036
  import { writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
19193
- import { join as join13 } from "path";
19037
+ import { join as join14 } from "path";
19194
19038
  import { tmpdir } from "os";
19195
19039
  function stopTunnel() {
19196
19040
  if (tunnelProcess) {
@@ -19294,6 +19138,7 @@ async function stop() {
19294
19138
  resetConfigCache();
19295
19139
  clearCustomCaslRules();
19296
19140
  clearSeedPermissions();
19141
+ _resetSecretResolver();
19297
19142
  await resetServeSPA();
19298
19143
  return;
19299
19144
  }
@@ -19329,6 +19174,7 @@ async function stop() {
19329
19174
  resetConfigCache();
19330
19175
  clearCustomCaslRules();
19331
19176
  clearSeedPermissions();
19177
+ _resetSecretResolver();
19332
19178
  await resetServeSPA();
19333
19179
  currentConfig = void 0;
19334
19180
  server = null;
@@ -19389,6 +19235,7 @@ var init_server = __esm({
19389
19235
  init_ensure_system_tables();
19390
19236
  init_load_config();
19391
19237
  init_tunnel();
19238
+ init_secret_resolver();
19392
19239
  server = null;
19393
19240
  gracefulShutdownRegistered = false;
19394
19241
  setupGracefulShutdown();
@@ -19444,10 +19291,11 @@ var init_hash = __esm({
19444
19291
  });
19445
19292
 
19446
19293
  // src/core/crypto/symmetric.ts
19447
- import { createCipheriv, createDecipheriv, randomBytes as randomBytes2, hkdfSync } from "crypto";
19294
+ import { createCipheriv, createDecipheriv, randomBytes as randomBytes3, hkdfSync } from "crypto";
19448
19295
  var init_symmetric = __esm({
19449
19296
  "src/core/crypto/symmetric.ts"() {
19450
19297
  "use strict";
19298
+ init_secret_resolver();
19451
19299
  }
19452
19300
  });
19453
19301
 
@@ -19559,6 +19407,13 @@ var init_events_api = __esm({
19559
19407
  }
19560
19408
  });
19561
19409
 
19410
+ // src/engine/capabilities-registry.ts
19411
+ var init_capabilities_registry = __esm({
19412
+ "src/engine/capabilities-registry.ts"() {
19413
+ "use strict";
19414
+ }
19415
+ });
19416
+
19562
19417
  // src/engine/context.ts
19563
19418
  import { ForbiddenError as CASLForbiddenError3, subject } from "@casl/ability";
19564
19419
  import { DEFAULT_TENANT_ID as DEFAULT_TENANT_ID2, DEFAULT_LOCALES as DEFAULT_LOCALES2 } from "@gzl10/nexus-sdk";
@@ -19585,6 +19440,7 @@ var init_context = __esm({
19585
19440
  init_plugin_ops();
19586
19441
  init_load_config();
19587
19442
  init_events_api();
19443
+ init_capabilities_registry();
19588
19444
  init_seed_runner();
19589
19445
  init_cache_manager();
19590
19446
  sharedCacheManager = null;
@@ -19603,6 +19459,7 @@ var init_engine = __esm({
19603
19459
  init_subject_extractor();
19604
19460
  init_definition_extractors();
19605
19461
  init_context();
19462
+ init_capabilities_registry();
19606
19463
  }
19607
19464
  });
19608
19465
 
@@ -19620,8 +19477,8 @@ __export(migrate_commands_exports, {
19620
19477
  handleUp: () => handleUp,
19621
19478
  loadModulesForMigration: () => loadModulesForMigration
19622
19479
  });
19623
- import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
19624
- import { join as join14 } from "path";
19480
+ import { readFileSync as readFileSync9, existsSync as existsSync12 } from "fs";
19481
+ import { join as join15 } from "path";
19625
19482
  import { pathToFileURL as pathToFileURL3 } from "url";
19626
19483
  import Table from "cli-table3";
19627
19484
  import { consola as consola2 } from "consola";
@@ -19631,15 +19488,15 @@ function scopeToSourceId(scope) {
19631
19488
  }
19632
19489
  async function loadSelfPlugin() {
19633
19490
  const projectPath2 = getProjectPath();
19634
- const pkgPath = join14(projectPath2, "package.json");
19635
- if (!existsSync11(pkgPath)) return;
19491
+ const pkgPath = join15(projectPath2, "package.json");
19492
+ if (!existsSync12(pkgPath)) return;
19636
19493
  try {
19637
- const pkg3 = JSON.parse(readFileSync8(pkgPath, "utf-8"));
19494
+ const pkg3 = JSON.parse(readFileSync9(pkgPath, "utf-8"));
19638
19495
  const pkgName = pkg3?.name;
19639
19496
  if (!pkgName || !/nexus-plugin-/.test(pkgName)) return;
19640
- const srcEntry = join14(projectPath2, "src", "index.ts");
19641
- const distEntry = join14(projectPath2, "dist", "index.js");
19642
- if (existsSync11(srcEntry)) {
19497
+ const srcEntry = join15(projectPath2, "src", "index.ts");
19498
+ const distEntry = join15(projectPath2, "dist", "index.js");
19499
+ if (existsSync12(srcEntry)) {
19643
19500
  try {
19644
19501
  const { tsImport } = await import("tsx/esm/api");
19645
19502
  const mod = await tsImport(
@@ -19649,7 +19506,7 @@ async function loadSelfPlugin() {
19649
19506
  const manifest = extractPluginManifest(mod);
19650
19507
  if (manifest) {
19651
19508
  if (!manifest.migrationsDir) {
19652
- manifest.migrationsDir = join14(projectPath2, "migrations");
19509
+ manifest.migrationsDir = join15(projectPath2, "migrations");
19653
19510
  }
19654
19511
  registerPlugin(manifest);
19655
19512
  return;
@@ -19658,13 +19515,13 @@ async function loadSelfPlugin() {
19658
19515
  console.error(` \u26A0 Failed to load plugin src/index.ts: ${err.message}`);
19659
19516
  }
19660
19517
  }
19661
- if (existsSync11(distEntry)) {
19518
+ if (existsSync12(distEntry)) {
19662
19519
  try {
19663
19520
  const mod = await import(pathToFileURL3(distEntry).href);
19664
19521
  const manifest = extractPluginManifest(mod);
19665
19522
  if (manifest) {
19666
19523
  if (!manifest.migrationsDir) {
19667
- manifest.migrationsDir = join14(projectPath2, "migrations");
19524
+ manifest.migrationsDir = join15(projectPath2, "migrations");
19668
19525
  }
19669
19526
  registerPlugin(manifest);
19670
19527
  return;
@@ -19983,7 +19840,7 @@ __export(db_commands_exports, {
19983
19840
  handleDbWipe: () => handleDbWipe
19984
19841
  });
19985
19842
  import { spawn as spawn2 } from "child_process";
19986
- import { isAbsolute as isAbsolute3, join as join15 } from "path";
19843
+ import { isAbsolute as isAbsolute3, join as join16 } from "path";
19987
19844
  import { statSync as statSync2 } from "fs";
19988
19845
  import { consola as consola3 } from "consola";
19989
19846
  async function handleDbWipe(options) {
@@ -20071,7 +19928,7 @@ function handleDbShell() {
20071
19928
  if (dbType === "sqlite") {
20072
19929
  let filename = url.replace(/^(file:|sqlite:)/, "");
20073
19930
  if (!isAbsolute3(filename)) {
20074
- filename = join15(getProjectPath(), "data", filename);
19931
+ filename = join16(getProjectPath(), "data", filename);
20075
19932
  }
20076
19933
  cmd = "sqlite3";
20077
19934
  args = [filename];
@@ -20116,7 +19973,7 @@ async function collectDbInfo() {
20116
19973
  if (url !== ":memory:" && !url.includes(":memory:")) {
20117
19974
  let filename = url.replace(/^(file:|sqlite:)/, "");
20118
19975
  if (!isAbsolute3(filename)) {
20119
- filename = join15(getProjectPath(), "data", filename);
19976
+ filename = join16(getProjectPath(), "data", filename);
20120
19977
  }
20121
19978
  try {
20122
19979
  const stat2 = statSync2(filename);
@@ -20173,8 +20030,8 @@ __export(plugin_commands_exports, {
20173
20030
  handlePluginList: () => handlePluginList,
20174
20031
  handlePluginRemove: () => handlePluginRemove
20175
20032
  });
20176
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
20177
- import { join as join16 } from "path";
20033
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
20034
+ import { join as join17 } from "path";
20178
20035
  import Table2 from "cli-table3";
20179
20036
  import { consola as consola4 } from "consola";
20180
20037
  import { OFFICIAL_PLUGINS as OFFICIAL_PLUGINS2 } from "@gzl10/nexus-sdk";
@@ -20182,10 +20039,10 @@ function pluginLabel(name) {
20182
20039
  return shortPluginName(name).split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
20183
20040
  }
20184
20041
  function readPluginVersion(projectPath2, pkgName) {
20185
- const pkgJsonPath = join16(projectPath2, "node_modules", pkgName, "package.json");
20186
- if (!existsSync12(pkgJsonPath)) return null;
20042
+ const pkgJsonPath = join17(projectPath2, "node_modules", pkgName, "package.json");
20043
+ if (!existsSync13(pkgJsonPath)) return null;
20187
20044
  try {
20188
- const pkg3 = JSON.parse(readFileSync9(pkgJsonPath, "utf-8"));
20045
+ const pkg3 = JSON.parse(readFileSync10(pkgJsonPath, "utf-8"));
20189
20046
  return pkg3.version ?? null;
20190
20047
  } catch {
20191
20048
  return null;
@@ -20471,19 +20328,19 @@ var sync_commands_exports = {};
20471
20328
  __export(sync_commands_exports, {
20472
20329
  handleSyncCommands: () => handleSyncCommands
20473
20330
  });
20474
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, readdirSync as readdirSync2, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
20475
- import { join as join17, basename as basename4 } from "path";
20331
+ import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync2, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
20332
+ import { join as join18, basename as basename4 } from "path";
20476
20333
  import { homedir } from "os";
20477
20334
  import { createConsola } from "consola";
20478
20335
  async function handleSyncCommands(options) {
20479
- const sourceDir = join17(getLibPath(), "claude-commands");
20480
- const targetDir = join17(homedir(), ".claude", "commands");
20481
- if (!existsSync13(sourceDir)) {
20336
+ const sourceDir = join18(getLibPath(), "claude-commands");
20337
+ const targetDir = join18(homedir(), ".claude", "commands");
20338
+ if (!existsSync14(sourceDir)) {
20482
20339
  logger2.warn(`Commands source not found: ${sourceDir}`);
20483
20340
  logger2.info("Make sure @gzl10/nexus-backend is properly installed.");
20484
20341
  return;
20485
20342
  }
20486
- if (!existsSync13(targetDir)) {
20343
+ if (!existsSync14(targetDir)) {
20487
20344
  if (options.dryRun) {
20488
20345
  logger2.info(`Would create: ${targetDir}`);
20489
20346
  } else {
@@ -20498,16 +20355,16 @@ async function handleSyncCommands(options) {
20498
20355
  }
20499
20356
  const result = { added: [], updated: [], unchanged: [] };
20500
20357
  for (const file of sourceFiles) {
20501
- const sourcePath = join17(sourceDir, file);
20502
- const targetPath = join17(targetDir, file);
20503
- const sourceContent = readFileSync10(sourcePath, "utf-8");
20504
- if (!existsSync13(targetPath)) {
20358
+ const sourcePath = join18(sourceDir, file);
20359
+ const targetPath = join18(targetDir, file);
20360
+ const sourceContent = readFileSync11(sourcePath, "utf-8");
20361
+ if (!existsSync14(targetPath)) {
20505
20362
  if (!options.dryRun) {
20506
20363
  writeFileSync3(targetPath, sourceContent, "utf-8");
20507
20364
  }
20508
20365
  result.added.push(file);
20509
20366
  } else {
20510
- const targetContent = readFileSync10(targetPath, "utf-8");
20367
+ const targetContent = readFileSync11(targetPath, "utf-8");
20511
20368
  if (sourceContent !== targetContent) {
20512
20369
  if (!options.dryRun) {
20513
20370
  writeFileSync3(targetPath, sourceContent, "utf-8");
@@ -20553,8 +20410,8 @@ __export(seed_commands_exports, {
20553
20410
  handleSeedExport: () => handleSeedExport,
20554
20411
  importSeedFiles: () => importSeedFiles
20555
20412
  });
20556
- import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4, readdirSync as readdirSync3, readFileSync as readFileSync11 } from "fs";
20557
- import { join as join18, basename as basename5 } from "path";
20413
+ import { existsSync as existsSync15, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4, readdirSync as readdirSync3, readFileSync as readFileSync12 } from "fs";
20414
+ import { join as join19, basename as basename5 } from "path";
20558
20415
  import { consola as consola5 } from "consola";
20559
20416
  function deserializeJsonFields(record, fields) {
20560
20417
  const result = { ...record };
@@ -20583,7 +20440,7 @@ async function handleSeedExport(entity) {
20583
20440
  const db3 = getDb();
20584
20441
  try {
20585
20442
  const modules = getOrderedModules();
20586
- const seedDir = join18(getProjectPath(), "data", "seeds");
20443
+ const seedDir = join19(getProjectPath(), "data", "seeds");
20587
20444
  const seedableEntities = [];
20588
20445
  for (const mod of modules) {
20589
20446
  for (const def of mod.definitions ?? []) {
@@ -20604,7 +20461,7 @@ async function handleSeedExport(entity) {
20604
20461
  }
20605
20462
  return;
20606
20463
  }
20607
- if (!existsSync14(seedDir)) {
20464
+ if (!existsSync15(seedDir)) {
20608
20465
  mkdirSync7(seedDir, { recursive: true });
20609
20466
  }
20610
20467
  for (const { module: modName, table, fields } of seedableEntities) {
@@ -20616,7 +20473,7 @@ async function handleSeedExport(entity) {
20616
20473
  const exported = rows.map(
20617
20474
  (row) => deserializeJsonFields(row, fields)
20618
20475
  );
20619
- const filePath = join18(seedDir, `${table}.json`);
20476
+ const filePath = join19(seedDir, `${table}.json`);
20620
20477
  writeFileSync4(filePath, JSON.stringify(exported, null, 2) + "\n", "utf-8");
20621
20478
  consola5.success(`${table}: exported ${rows.length} records to data/seeds/${table}.json (module: ${modName})`);
20622
20479
  }
@@ -20628,8 +20485,8 @@ async function handleSeedExport(entity) {
20628
20485
  }
20629
20486
  }
20630
20487
  async function importSeedFiles(db3, modules, logger3) {
20631
- const seedDir = join18(getProjectPath(), "data", "seeds");
20632
- if (!existsSync14(seedDir)) return;
20488
+ const seedDir = join19(getProjectPath(), "data", "seeds");
20489
+ if (!existsSync15(seedDir)) return;
20633
20490
  const files = readdirSync3(seedDir).filter((f) => f.endsWith(".json"));
20634
20491
  if (files.length === 0) return;
20635
20492
  const seedableDefs = /* @__PURE__ */ new Map();
@@ -20650,8 +20507,8 @@ async function importSeedFiles(db3, modules, logger3) {
20650
20507
  logger3.debug(`data/seeds/${file}: skipped (entity "${table}" is not seedable)`);
20651
20508
  continue;
20652
20509
  }
20653
- const filePath = join18(seedDir, file);
20654
- const raw = readFileSync11(filePath, "utf-8");
20510
+ const filePath = join19(seedDir, file);
20511
+ const raw = readFileSync12(filePath, "utf-8");
20655
20512
  let records;
20656
20513
  try {
20657
20514
  records = JSON.parse(raw);
@@ -20698,12 +20555,12 @@ if (!nodeEnv || nodeEnv === "development") {
20698
20555
  }
20699
20556
 
20700
20557
  // src/cli.ts
20701
- import { readFileSync as readFileSync12 } from "fs";
20558
+ import { readFileSync as readFileSync13 } from "fs";
20702
20559
  import { fileURLToPath as fileURLToPath3 } from "url";
20703
- import { dirname as dirname8, join as join19 } from "path";
20560
+ import { dirname as dirname8, join as join20 } from "path";
20704
20561
  import { Command } from "commander";
20705
20562
  var __dirname2 = dirname8(fileURLToPath3(import.meta.url));
20706
- var pkg2 = JSON.parse(readFileSync12(join19(__dirname2, "..", "package.json"), "utf-8"));
20563
+ var pkg2 = JSON.parse(readFileSync13(join20(__dirname2, "..", "package.json"), "utf-8"));
20707
20564
  var program = new Command();
20708
20565
  program.name("nexus").description("Nexus Backend CLI").version(pkg2.version);
20709
20566
  program.command("info").description("Show Nexus environment, database, plugins, and paths").option("--json", "Output as JSON").action(async (options) => {