@gzl10/nexus-backend 0.18.0 → 0.19.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
@@ -47,7 +47,7 @@ var init_env = __esm({
47
47
  envSchema = z.object({
48
48
  NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
49
49
  PORT: z.coerce.number().default(3e3),
50
- CORS_ORIGIN: z.string().default("http://localhost:3001"),
50
+ CORS_ORIGIN: z.string().default("*"),
51
51
  BACKEND_URL: z.string().optional(),
52
52
  DATABASE_URL: z.string().default("file:./dev.db"),
53
53
  REDIS_URL: z.string().url().optional(),
@@ -764,6 +764,14 @@ async function isWorkspacePackage(name) {
764
764
  }
765
765
  }
766
766
  async function installPlugin(name, opts) {
767
+ const projectPath2 = opts?.projectPath ?? process.cwd();
768
+ const pkgPath = join5(projectPath2, "package.json");
769
+ if (existsSync4(pkgPath)) {
770
+ const pkg4 = JSON.parse(readFileSync3(pkgPath, "utf-8"));
771
+ if (pkg4.name === "@gzl10/nexus-backend") {
772
+ throw new Error("Cannot install plugins inside @gzl10/nexus-backend. Run this command from a Nexus project directory.");
773
+ }
774
+ }
767
775
  const isWorkspace = await isWorkspacePackage(name);
768
776
  let pkg3;
769
777
  if (opts?.version) {
@@ -780,11 +788,28 @@ async function installPlugin(name, opts) {
780
788
  plugins[name] = { enabled: true };
781
789
  writePluginsFile(plugins, filePath);
782
790
  }
791
+ function isPackageInstalled(name, projectPath2) {
792
+ const base = projectPath2 || process.cwd();
793
+ const pkgPath = join5(base, "package.json");
794
+ try {
795
+ const pkg3 = JSON.parse(readFileSync3(pkgPath, "utf-8"));
796
+ return !!(pkg3.dependencies?.[name] || pkg3.devDependencies?.[name]);
797
+ } catch {
798
+ return false;
799
+ }
800
+ }
783
801
  async function uninstallPlugin(name, projectPath2) {
784
- await execAsync(`pnpm remove ${name}`);
785
802
  const filePath = getPluginsFilePath(projectPath2);
786
803
  const plugins = readPluginsFile(filePath);
787
- if (name in plugins) {
804
+ const isRegistered = name in plugins;
805
+ const isInstalled = isPackageInstalled(name, projectPath2);
806
+ if (!isRegistered && !isInstalled) {
807
+ throw new Error(`Plugin ${shortPluginName(name)} is not installed`);
808
+ }
809
+ if (isInstalled) {
810
+ await execAsync(`pnpm remove ${name}`);
811
+ }
812
+ if (isRegistered) {
788
813
  delete plugins[name];
789
814
  writePluginsFile(plugins, filePath);
790
815
  }
@@ -823,26 +848,10 @@ function initCli() {
823
848
  initLoggerService({ ...config3, level: "error", sentry: void 0 });
824
849
  setLoggerInstance(getPinoLogger());
825
850
  }
826
- function handleCliError(err) {
827
- if (err instanceof CliError) {
828
- consola.error(err.message);
829
- if (err.hint) consola.info(err.hint);
830
- process.exit(1);
831
- }
832
- throw err;
833
- }
834
- var CliError;
835
851
  var init_shared = __esm({
836
852
  "src/cli/shared.ts"() {
837
853
  "use strict";
838
854
  init_logger();
839
- CliError = class extends Error {
840
- constructor(message, hint) {
841
- super(message);
842
- this.hint = hint;
843
- this.name = "CliError";
844
- }
845
- };
846
855
  }
847
856
  });
848
857
 
@@ -1520,6 +1529,7 @@ var init_definitions = __esm({
1520
1529
  };
1521
1530
  mastersEntity = {
1522
1531
  table: "masters",
1532
+ seedable: true,
1523
1533
  routePrefix: "/",
1524
1534
  label: { en: "Master", es: "Maestro" },
1525
1535
  labelPlural: { en: "Masters", es: "Maestros" },
@@ -1551,14 +1561,15 @@ var init_definitions = __esm({
1551
1561
  meta: { sortable: true, searchable: true }
1552
1562
  }),
1553
1563
  label: useLocalizedField({ label: { en: "Name", es: "Nombre" } }),
1554
- order: orderField,
1564
+ order: { ...orderField, meta: { ...orderField.meta, showInDisplay: false } },
1555
1565
  is_active: isActiveField,
1556
1566
  metadata: useJsonField({
1557
1567
  label: { en: "Metadata", es: "Metadatos" },
1558
1568
  hint: {
1559
1569
  en: "Type-specific fields (symbol, flag, etc.)",
1560
1570
  es: "Campos espec\xEDficos del tipo"
1561
- }
1571
+ },
1572
+ meta: { showInDisplay: false }
1562
1573
  })
1563
1574
  },
1564
1575
  hooks: () => ({
@@ -1567,6 +1578,12 @@ var init_definitions = __esm({
1567
1578
  data["id"] = `${data["type"]}:${data["code"]}`;
1568
1579
  }
1569
1580
  return data;
1581
+ },
1582
+ beforeUpdate: async (_id, data) => {
1583
+ if ("type" in data || "code" in data) {
1584
+ throw new Error("Cannot update type or code of a master record. Delete and recreate instead.");
1585
+ }
1586
+ return data;
1570
1587
  }
1571
1588
  }),
1572
1589
  defaultSort: { field: "order", order: "asc" },
@@ -1595,8 +1612,8 @@ function createMasterRegistry() {
1595
1612
  */
1596
1613
  async seed(ctx) {
1597
1614
  for (const reg of registrations) {
1598
- const { type: type2, entries, seed: seed5 } = reg;
1599
- if (seed5 === "if-empty") {
1615
+ const { type: type2, entries, seed: seed6 } = reg;
1616
+ if (seed6 === "if-empty") {
1600
1617
  const existing = await ctx.db.knex("masters").where({ type: type2 }).first();
1601
1618
  if (existing) continue;
1602
1619
  }
@@ -1609,12 +1626,12 @@ function createMasterRegistry() {
1609
1626
  is_active: entry.is_active ?? true,
1610
1627
  metadata: entry.metadata ? JSON.stringify(entry.metadata) : null
1611
1628
  }));
1612
- if (seed5 === "always") {
1629
+ if (seed6 === "always") {
1613
1630
  for (const row of rows) {
1614
1631
  await ctx.db.knex("masters").insert(row).onConflict(["type", "code"]).merge();
1615
1632
  }
1616
1633
  } else {
1617
- await ctx.db.knex("masters").insert(rows);
1634
+ await ctx.db.knex("masters").insert(rows).onConflict(["type", "code"]).ignore();
1618
1635
  }
1619
1636
  }
1620
1637
  },
@@ -8047,15 +8064,12 @@ var init_document_types = __esm({
8047
8064
  }
8048
8065
  });
8049
8066
 
8050
- // src/modules/masters/index.ts
8051
- var PREDEFINED_MASTERS, mastersModule;
8052
- var init_masters = __esm({
8053
- "src/modules/masters/index.ts"() {
8067
+ // src/modules/masters/constants.ts
8068
+ var DEFAULT_MASTER_TYPES, PREDEFINED_MASTERS;
8069
+ var init_constants = __esm({
8070
+ "src/modules/masters/constants.ts"() {
8054
8071
  "use strict";
8055
- init_definitions();
8056
- init_registry2();
8057
- init_definitions();
8058
- init_registry2();
8072
+ DEFAULT_MASTER_TYPES = ["languages", "timezones"];
8059
8073
  PREDEFINED_MASTERS = {
8060
8074
  currencies: () => Promise.resolve().then(() => (init_currencies(), currencies_exports)).then((m) => m.default),
8061
8075
  languages: () => Promise.resolve().then(() => (init_languages(), languages_exports)).then((m) => m.default),
@@ -8072,15 +8086,137 @@ var init_masters = __esm({
8072
8086
  "phone-prefixes": () => Promise.resolve().then(() => (init_phone_prefixes(), phone_prefixes_exports)).then((m) => m.default),
8073
8087
  "document-types": () => Promise.resolve().then(() => (init_document_types(), document_types_exports)).then((m) => m.default)
8074
8088
  };
8089
+ }
8090
+ });
8091
+
8092
+ // src/modules/masters/actions/install-type.ts
8093
+ import { useSelectField as useSelectField2 } from "@gzl10/nexus-sdk/fields";
8094
+ var installTypeAction;
8095
+ var init_install_type = __esm({
8096
+ "src/modules/masters/actions/install-type.ts"() {
8097
+ "use strict";
8098
+ init_constants();
8099
+ installTypeAction = {
8100
+ key: "install-type",
8101
+ scope: "module",
8102
+ label: { en: "Install Master Type", es: "Instalar Tipo de Maestro" },
8103
+ icon: "mdi:database-plus",
8104
+ variant: "primary",
8105
+ output: {},
8106
+ input: {
8107
+ type: useSelectField2({
8108
+ label: { en: "Master Type", es: "Tipo de Maestro" },
8109
+ required: true,
8110
+ options: Object.keys(PREDEFINED_MASTERS).filter((t) => !DEFAULT_MASTER_TYPES.includes(t)).map((t) => ({
8111
+ value: t,
8112
+ label: t.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
8113
+ }))
8114
+ })
8115
+ },
8116
+ handler: async (ctx, input) => {
8117
+ if (process.env["NODE_ENV"] === "production") {
8118
+ throw new ctx.core.errors.ForbiddenError("Master type management is only available in development");
8119
+ }
8120
+ const { type: type2 } = input;
8121
+ const loader = PREDEFINED_MASTERS[type2];
8122
+ if (!loader) {
8123
+ throw new ctx.core.errors.AppError(`Unknown predefined master type: ${type2}`, 400);
8124
+ }
8125
+ const existing = await ctx.db.knex("masters").where({ type: type2 }).first();
8126
+ if (existing) {
8127
+ throw new ctx.core.errors.ConflictError(`Master type "${type2}" is already installed`);
8128
+ }
8129
+ const entries = await loader();
8130
+ const rows = entries.map((entry, i) => ({
8131
+ id: `${type2}:${entry.code}`,
8132
+ type: type2,
8133
+ code: entry.code,
8134
+ label: JSON.stringify(typeof entry.label === "string" ? { en: entry.label } : entry.label),
8135
+ order: entry.order ?? i,
8136
+ is_active: entry.is_active ?? true,
8137
+ metadata: entry.metadata ? JSON.stringify(entry.metadata) : null
8138
+ }));
8139
+ await ctx.db.knex("masters").insert(rows).onConflict(["type", "code"]).ignore();
8140
+ return { installed: type2, count: rows.length };
8141
+ }
8142
+ };
8143
+ }
8144
+ });
8145
+
8146
+ // src/modules/masters/actions/uninstall-type.ts
8147
+ import { useTextField as useTextField3 } from "@gzl10/nexus-sdk/fields";
8148
+ var uninstallTypeAction;
8149
+ var init_uninstall_type = __esm({
8150
+ "src/modules/masters/actions/uninstall-type.ts"() {
8151
+ "use strict";
8152
+ init_constants();
8153
+ uninstallTypeAction = {
8154
+ key: "uninstall-type",
8155
+ scope: "module",
8156
+ label: { en: "Uninstall Master Type", es: "Desinstalar Tipo de Maestro" },
8157
+ icon: "mdi:database-minus",
8158
+ variant: "danger",
8159
+ output: {},
8160
+ confirm: {
8161
+ type: "simple",
8162
+ title: { en: "Uninstall Master Type", es: "Desinstalar Tipo de Maestro" },
8163
+ message: {
8164
+ en: "This will delete ALL records of the selected type. This action cannot be undone.",
8165
+ es: "Esto eliminar\xE1 TODOS los registros del tipo seleccionado. Esta acci\xF3n no se puede deshacer."
8166
+ }
8167
+ },
8168
+ input: {
8169
+ type: useTextField3({
8170
+ label: { en: "Type slug to uninstall", es: "Slug del tipo a desinstalar" },
8171
+ required: true,
8172
+ hint: {
8173
+ en: 'Enter the master type slug (e.g., "currencies", "countries")',
8174
+ es: 'Introduce el slug del tipo (ej: "currencies", "countries")'
8175
+ }
8176
+ })
8177
+ },
8178
+ handler: async (ctx, input) => {
8179
+ if (process.env["NODE_ENV"] === "production") {
8180
+ throw new ctx.core.errors.ForbiddenError("Master type management is only available in development");
8181
+ }
8182
+ const { type: type2 } = input;
8183
+ if (DEFAULT_MASTER_TYPES.includes(type2)) {
8184
+ throw new ctx.core.errors.AppError(`Cannot uninstall default master type "${type2}" (required by core)`, 400);
8185
+ }
8186
+ const existing = await ctx.db.knex("masters").where({ type: type2 }).first();
8187
+ if (!existing) {
8188
+ throw new ctx.core.errors.NotFoundError(`Master type "${type2}" is not installed`);
8189
+ }
8190
+ const deleted = await ctx.db.knex("masters").where({ type: type2 }).del();
8191
+ return { uninstalled: type2, count: deleted };
8192
+ }
8193
+ };
8194
+ }
8195
+ });
8196
+
8197
+ // src/modules/masters/index.ts
8198
+ var mastersModule;
8199
+ var init_masters = __esm({
8200
+ "src/modules/masters/index.ts"() {
8201
+ "use strict";
8202
+ init_definitions();
8203
+ init_registry2();
8204
+ init_constants();
8205
+ init_install_type();
8206
+ init_uninstall_type();
8207
+ init_definitions();
8208
+ init_registry2();
8209
+ init_constants();
8075
8210
  mastersModule = {
8076
8211
  name: "masters",
8077
8212
  type: "core",
8078
- label: { en: "Master Data", es: "Datos maestros" },
8213
+ label: { en: "Masters", es: "Maestros" },
8079
8214
  icon: "mdi:database-outline",
8080
8215
  description: { en: "Reference data catalogs", es: "Cat\xE1logos de datos de referencia" },
8081
- category: "data",
8216
+ category: "settings",
8082
8217
  routePrefix: "/masters",
8083
8218
  definitions: [mastersEntity],
8219
+ actions: [installTypeAction, uninstallTypeAction],
8084
8220
  init: (ctx) => {
8085
8221
  if (!ctx.services.has("masters")) {
8086
8222
  ctx.services.register("masters", createMasterRegistry());
@@ -8091,13 +8227,14 @@ var init_masters = __esm({
8091
8227
  ctx.services.register("masters", createMasterRegistry());
8092
8228
  }
8093
8229
  const registry2 = ctx.services.get("masters");
8094
- const configMasters = ctx.config.resolved["masters"];
8095
- const typesToSeed = !configMasters || configMasters === "*" ? Object.keys(PREDEFINED_MASTERS) : configMasters.filter((t) => t in PREDEFINED_MASTERS);
8096
- for (const type2 of typesToSeed) {
8097
- const loader = PREDEFINED_MASTERS[type2];
8098
- if (!loader) continue;
8099
- const entries = await loader();
8100
- registry2.register(type2, entries, { seed: "if-empty" });
8230
+ const existing = await ctx.db.knex("masters").first();
8231
+ if (!existing) {
8232
+ for (const type2 of DEFAULT_MASTER_TYPES) {
8233
+ const loader = PREDEFINED_MASTERS[type2];
8234
+ if (!loader) continue;
8235
+ const entries = await loader();
8236
+ registry2.register(type2, entries, { seed: "if-empty" });
8237
+ }
8101
8238
  }
8102
8239
  await registry2.seed(ctx);
8103
8240
  }
@@ -8361,6 +8498,7 @@ function toPageDTO(page) {
8361
8498
  dataSource: page.dataSource,
8362
8499
  widgets: page.widgets,
8363
8500
  component: page.component,
8501
+ contentEndpoint: page.contentEndpoint,
8364
8502
  meta: page.meta,
8365
8503
  layout: page.layout
8366
8504
  };
@@ -8624,7 +8762,7 @@ var init_system_routes = __esm({
8624
8762
 
8625
8763
  // src/modules/system/system.entity.ts
8626
8764
  import * as os from "os";
8627
- import { useIconField, useTextField as useTextField3, useSelectField as useSelectField2, useNumberField as useNumberField2, useCheckboxField, useTagsField, useNameField, useDescriptionField } from "@gzl10/nexus-sdk/fields";
8765
+ import { useIconField, useTextField as useTextField4, useSelectField as useSelectField3, useNumberField as useNumberField2, useCheckboxField, useTagsField, useNameField, useDescriptionField } from "@gzl10/nexus-sdk/fields";
8628
8766
  var moduleEntity, osEntity;
8629
8767
  var init_system_entity = __esm({
8630
8768
  "src/modules/system/system.entity.ts"() {
@@ -8642,7 +8780,7 @@ var init_system_entity = __esm({
8642
8780
  name: useNameField({
8643
8781
  size: 50
8644
8782
  }),
8645
- label: useTextField3({
8783
+ label: useTextField4({
8646
8784
  label: { en: "Label", es: "Etiqueta" },
8647
8785
  size: 100,
8648
8786
  nullable: false,
@@ -8650,7 +8788,7 @@ var init_system_entity = __esm({
8650
8788
  }),
8651
8789
  icon: useIconField({ label: { en: "Icon", es: "Icono" }, size: 50 }),
8652
8790
  type: {
8653
- ...useSelectField2({
8791
+ ...useSelectField3({
8654
8792
  label: { en: "Type", es: "Tipo" },
8655
8793
  options: [
8656
8794
  { value: "core", label: { en: "Core", es: "Core" } },
@@ -8666,7 +8804,7 @@ var init_system_entity = __esm({
8666
8804
  description: useDescriptionField({
8667
8805
  mode: "text"
8668
8806
  }),
8669
- routePrefix: useTextField3({
8807
+ routePrefix: useTextField4({
8670
8808
  label: { en: "Route", es: "Ruta" },
8671
8809
  size: 50,
8672
8810
  nullable: true
@@ -8724,14 +8862,14 @@ var init_system_entity = __esm({
8724
8862
  order: 1,
8725
8863
  refreshInterval: 5e3,
8726
8864
  fields: {
8727
- hostname: useTextField3({
8865
+ hostname: useTextField4({
8728
8866
  label: { en: "Hostname", es: "Nombre de servidor" },
8729
8867
  size: 100,
8730
8868
  nullable: false,
8731
8869
  inputProps: { order: 1 }
8732
8870
  }),
8733
8871
  platform: {
8734
- ...useSelectField2({
8872
+ ...useSelectField3({
8735
8873
  label: { en: "Platform", es: "Plataforma" },
8736
8874
  options: [
8737
8875
  { value: "darwin", label: { en: "macOS", es: "macOS" } },
@@ -8745,7 +8883,7 @@ var init_system_entity = __esm({
8745
8883
  inputProps: { order: 2 }
8746
8884
  },
8747
8885
  arch: {
8748
- ...useSelectField2({
8886
+ ...useSelectField3({
8749
8887
  label: { en: "Architecture", es: "Arquitectura" },
8750
8888
  options: [
8751
8889
  { value: "x64", label: { en: "x64", es: "x64" } },
@@ -8758,7 +8896,7 @@ var init_system_entity = __esm({
8758
8896
  inputProps: { order: 3 }
8759
8897
  },
8760
8898
  type: {
8761
- ...useTextField3({
8899
+ ...useTextField4({
8762
8900
  label: { en: "Type", es: "Tipo" },
8763
8901
  size: 30,
8764
8902
  nullable: false
@@ -8766,7 +8904,7 @@ var init_system_entity = __esm({
8766
8904
  inputProps: { order: 4 }
8767
8905
  },
8768
8906
  release: {
8769
- ...useTextField3({
8907
+ ...useTextField4({
8770
8908
  label: { en: "Release", es: "Versi\xF3n" },
8771
8909
  size: 50,
8772
8910
  nullable: false
@@ -8789,7 +8927,7 @@ var init_system_entity = __esm({
8789
8927
  inputProps: { order: 7, format: "duration" }
8790
8928
  },
8791
8929
  cpuModel: {
8792
- ...useTextField3({
8930
+ ...useTextField4({
8793
8931
  label: { en: "CPU Model", es: "Modelo de CPU" },
8794
8932
  size: 100,
8795
8933
  nullable: false
@@ -8855,7 +8993,7 @@ var init_system_entity = __esm({
8855
8993
  });
8856
8994
 
8857
8995
  // src/modules/system/migration-history.entity.ts
8858
- import { useIdField as useIdField2, useTextField as useTextField4, useNumberField as useNumberField3, useSelectField as useSelectField3, useDatetimeField as useDatetimeField2, useTextareaField as useTextareaField2 } from "@gzl10/nexus-sdk/fields";
8996
+ import { useIdField as useIdField2, useTextField as useTextField5, useNumberField as useNumberField3, useSelectField as useSelectField4, useDatetimeField as useDatetimeField2, useTextareaField as useTextareaField2 } from "@gzl10/nexus-sdk/fields";
8859
8997
  var migrationHistoryEntity;
8860
8998
  var init_migration_history_entity = __esm({
8861
8999
  "src/modules/system/migration-history.entity.ts"() {
@@ -8872,9 +9010,9 @@ var init_migration_history_entity = __esm({
8872
9010
  calendarFrom: "executed_at",
8873
9011
  fields: {
8874
9012
  id: useIdField2(),
8875
- name: useTextField4({ label: { en: "Migration Name", es: "Nombre de la Migraci\xF3n" }, required: true, size: 255, unique: true, meta: { sortable: true, searchable: true } }),
9013
+ name: useTextField5({ label: { en: "Migration Name", es: "Nombre de la Migraci\xF3n" }, required: true, size: 255, unique: true, meta: { sortable: true, searchable: true } }),
8876
9014
  batch: useNumberField3({ label: { en: "Batch", es: "Lote" }, required: true, meta: { sortable: true } }),
8877
- status: useSelectField3({
9015
+ status: useSelectField4({
8878
9016
  label: { en: "Status", es: "Estado" },
8879
9017
  options: [
8880
9018
  { value: "running", label: { en: "Running", es: "Ejecutando" } },
@@ -8906,7 +9044,7 @@ var init_migration_history_entity = __esm({
8906
9044
  });
8907
9045
 
8908
9046
  // src/modules/system/env-config.entity.ts
8909
- import { useTextField as useTextField5, useSelectField as useSelectField4, useCheckboxField as useCheckboxField2 } from "@gzl10/nexus-sdk/fields";
9047
+ import { useTextField as useTextField6, useSelectField as useSelectField5, useCheckboxField as useCheckboxField2 } from "@gzl10/nexus-sdk/fields";
8910
9048
  function maskValue(value, sensitive) {
8911
9049
  if (!sensitive) return value;
8912
9050
  try {
@@ -8931,14 +9069,14 @@ var init_env_config_entity = __esm({
8931
9069
  routePrefix: "/env-config",
8932
9070
  defaultSort: { field: "category", order: "asc" },
8933
9071
  fields: {
8934
- name: useTextField5({
9072
+ name: useTextField6({
8935
9073
  label: { en: "Variable", es: "Variable" },
8936
9074
  size: 100,
8937
9075
  nullable: false,
8938
9076
  meta: { sortable: true, searchable: true }
8939
9077
  }),
8940
9078
  category: {
8941
- ...useSelectField4({
9079
+ ...useSelectField5({
8942
9080
  label: { en: "Category", es: "Categor\xEDa" },
8943
9081
  options: [
8944
9082
  { value: "server", label: { en: "Server", es: "Servidor" } },
@@ -8953,18 +9091,18 @@ var init_env_config_entity = __esm({
8953
9091
  meta: { sortable: true }
8954
9092
  })
8955
9093
  },
8956
- source: useTextField5({
9094
+ source: useTextField6({
8957
9095
  label: { en: "Source", es: "Origen" },
8958
9096
  size: 50,
8959
9097
  nullable: false,
8960
9098
  meta: { sortable: true }
8961
9099
  }),
8962
- value: useTextField5({
9100
+ value: useTextField6({
8963
9101
  label: { en: "Value", es: "Valor" },
8964
9102
  size: 255,
8965
9103
  nullable: true
8966
9104
  }),
8967
- default: useTextField5({
9105
+ default: useTextField6({
8968
9106
  label: { en: "Default", es: "Por defecto" },
8969
9107
  size: 100,
8970
9108
  nullable: true
@@ -9670,7 +9808,7 @@ var init_system = __esm({
9670
9808
  });
9671
9809
 
9672
9810
  // src/modules/ui-settings/ui-branding.entity.ts
9673
- import { useTextField as useTextField6, useImageField } from "@gzl10/nexus-sdk/fields";
9811
+ import { useTextField as useTextField7, useImageField } from "@gzl10/nexus-sdk/fields";
9674
9812
  var uiBrandingEntity;
9675
9813
  var init_ui_branding_entity = __esm({
9676
9814
  "src/modules/ui-settings/ui-branding.entity.ts"() {
@@ -9690,7 +9828,7 @@ var init_ui_branding_entity = __esm({
9690
9828
  favicon: null
9691
9829
  },
9692
9830
  fields: {
9693
- appName: useTextField6({
9831
+ appName: useTextField7({
9694
9832
  label: { en: "App Name", es: "Nombre de la App" },
9695
9833
  hint: { en: "Displayed in the header, browser tab and emails", es: "Se muestra en el header, pesta\xF1a del navegador y emails" },
9696
9834
  size: 100,
@@ -9731,7 +9869,7 @@ var init_ui_branding_entity = __esm({
9731
9869
  });
9732
9870
 
9733
9871
  // src/modules/ui-settings/ui-theme.entity.ts
9734
- import { useSelectField as useSelectField5, useColorField } from "@gzl10/nexus-sdk/fields";
9872
+ import { useSelectField as useSelectField6, useColorField } from "@gzl10/nexus-sdk/fields";
9735
9873
  var uiThemeEntity;
9736
9874
  var init_ui_theme_entity = __esm({
9737
9875
  "src/modules/ui-settings/ui-theme.entity.ts"() {
@@ -9756,7 +9894,7 @@ var init_ui_theme_entity = __esm({
9756
9894
  },
9757
9895
  fields: {
9758
9896
  // === Typography ===
9759
- font: useSelectField5({
9897
+ font: useSelectField6({
9760
9898
  label: { en: "Font", es: "Fuente" },
9761
9899
  hint: { en: "Primary font for headings and UI elements", es: "Fuente principal para t\xEDtulos y elementos de interfaz" },
9762
9900
  options: [
@@ -9769,7 +9907,7 @@ var init_ui_theme_entity = __esm({
9769
9907
  ]
9770
9908
  }),
9771
9909
  // === Theme & Colors ===
9772
- theme: useSelectField5({
9910
+ theme: useSelectField6({
9773
9911
  label: { en: "Theme", es: "Tema" },
9774
9912
  hint: { en: "System follows your device preferences", es: "Sistema sigue las preferencias de tu dispositivo" },
9775
9913
  options: [
@@ -9778,7 +9916,7 @@ var init_ui_theme_entity = __esm({
9778
9916
  { value: "system", label: { en: "System", es: "Sistema" } }
9779
9917
  ]
9780
9918
  }),
9781
- dopamineTheme: useSelectField5({
9919
+ dopamineTheme: useSelectField6({
9782
9920
  label: { en: "Dopamine Theme", es: "Tema Dopamina" },
9783
9921
  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)" },
9784
9922
  options: [
@@ -9796,7 +9934,7 @@ var init_ui_theme_entity = __esm({
9796
9934
  ]
9797
9935
  }),
9798
9936
  // === Login Layout ===
9799
- loginLayout: useSelectField5({
9937
+ loginLayout: useSelectField6({
9800
9938
  label: { en: "Login Layout", es: "Dise\xF1o de Login" },
9801
9939
  hint: { en: "Visual layout for authentication pages", es: "Dise\xF1o visual para p\xE1ginas de autenticaci\xF3n" },
9802
9940
  options: [
@@ -9827,7 +9965,7 @@ var init_ui_theme_entity = __esm({
9827
9965
  });
9828
9966
 
9829
9967
  // src/modules/ui-settings/ui-effects.entity.ts
9830
- import { useSelectField as useSelectField6, useSwitchField as useSwitchField2 } from "@gzl10/nexus-sdk/fields";
9968
+ import { useSelectField as useSelectField7, useSwitchField as useSwitchField2 } from "@gzl10/nexus-sdk/fields";
9831
9969
  var uiEffectsEntity;
9832
9970
  var init_ui_effects_entity = __esm({
9833
9971
  "src/modules/ui-settings/ui-effects.entity.ts"() {
@@ -9847,7 +9985,7 @@ var init_ui_effects_entity = __esm({
9847
9985
  enableOrganicShapes: false
9848
9986
  },
9849
9987
  fields: {
9850
- glassIntensity: useSelectField6({
9988
+ glassIntensity: useSelectField7({
9851
9989
  label: { en: "Glass Intensity", es: "Intensidad Glass" },
9852
9990
  hint: { en: "Glassmorphism blur effect on cards and modals", es: "Efecto de desenfoque glassmorphism en cards y modales" },
9853
9991
  options: [
@@ -9857,7 +9995,7 @@ var init_ui_effects_entity = __esm({
9857
9995
  { value: "high", label: { en: "High", es: "Alta" } }
9858
9996
  ]
9859
9997
  }),
9860
- borderStyle: useSelectField6({
9998
+ borderStyle: useSelectField7({
9861
9999
  label: { en: "Border Style", es: "Estilo de Bordes" },
9862
10000
  hint: { en: "Corner radius for buttons, cards and inputs", es: "Radio de esquinas para botones, cards e inputs" },
9863
10001
  options: [
@@ -9891,7 +10029,7 @@ var init_ui_effects_entity = __esm({
9891
10029
  });
9892
10030
 
9893
10031
  // src/modules/ui-settings/ui-accessibility.entity.ts
9894
- import { useSelectField as useSelectField7, useSwitchField as useSwitchField3 } from "@gzl10/nexus-sdk/fields";
10032
+ import { useSelectField as useSelectField8, useSwitchField as useSwitchField3 } from "@gzl10/nexus-sdk/fields";
9895
10033
  var uiAccessibilityEntity;
9896
10034
  var init_ui_accessibility_entity = __esm({
9897
10035
  "src/modules/ui-settings/ui-accessibility.entity.ts"() {
@@ -9910,7 +10048,7 @@ var init_ui_accessibility_entity = __esm({
9910
10048
  highContrast: false
9911
10049
  },
9912
10050
  fields: {
9913
- typographyScale: useSelectField7({
10051
+ typographyScale: useSelectField8({
9914
10052
  label: { en: "Typography Scale", es: "Escala Tipogr\xE1fica" },
9915
10053
  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)" },
9916
10054
  options: [
@@ -10901,7 +11039,7 @@ var init_storage_service = __esm({
10901
11039
  });
10902
11040
 
10903
11041
  // src/modules/storage/storage.entity.ts
10904
- import { useIdField as useIdField3, useTextField as useTextField7, useSelectField as useSelectField8, useUrlField, useNumberField as useNumberField4, useCheckboxField as useCheckboxField3, useJsonField as useJsonField2, useMetadataField, usePublicField } from "@gzl10/nexus-sdk/fields";
11042
+ 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";
10905
11043
  var DEFAULT_MAX_SIZE2, storageConfigEntity, storageFilesEntity;
10906
11044
  var init_storage_entity = __esm({
10907
11045
  "src/modules/storage/storage.entity.ts"() {
@@ -10927,7 +11065,7 @@ var init_storage_entity = __esm({
10927
11065
  },
10928
11066
  fields: {
10929
11067
  id: useIdField3(),
10930
- scope: useTextField7({
11068
+ scope: useTextField8({
10931
11069
  label: { en: "Scope", es: "\xC1mbito" },
10932
11070
  disabled: true,
10933
11071
  size: 100,
@@ -10936,7 +11074,7 @@ var init_storage_entity = __esm({
10936
11074
  hint: { en: "Unique identifier (e.g. default_filesystem, default_s3)", es: "Identificador \xFAnico (ej: default_filesystem, default_s3)" }
10937
11075
  }),
10938
11076
  driver: {
10939
- ...useSelectField8({
11077
+ ...useSelectField9({
10940
11078
  label: { en: "Driver", es: "Controlador" },
10941
11079
  required: true,
10942
11080
  hint: { en: "Storage backend", es: "Backend de almacenamiento" },
@@ -10959,7 +11097,7 @@ var init_storage_entity = __esm({
10959
11097
  nullable: false,
10960
11098
  displayProps: { format: "bytes" }
10961
11099
  }),
10962
- allowed_mime_types: useTextField7({
11100
+ allowed_mime_types: useTextField8({
10963
11101
  label: { en: "Allowed MIME Types", es: "Tipos MIME permitidos" },
10964
11102
  hint: { en: "Allowed types separated by comma (e.g. image/*,application/pdf)", es: "Tipos permitidos separados por coma (ej: image/*,application/pdf)" },
10965
11103
  size: 1e3,
@@ -11124,21 +11262,21 @@ var init_storage_entity = __esm({
11124
11262
  ],
11125
11263
  fields: {
11126
11264
  id: useIdField3(),
11127
- filename: useTextField7({
11265
+ filename: useTextField8({
11128
11266
  label: { en: "Original Filename", es: "Nombre original" },
11129
11267
  required: true,
11130
11268
  size: 255,
11131
11269
  nullable: false,
11132
11270
  meta: { sortable: true, searchable: true }
11133
11271
  }),
11134
- disk_filename: useTextField7({
11272
+ disk_filename: useTextField8({
11135
11273
  label: { en: "Disk Filename", es: "Nombre en disco" },
11136
11274
  required: true,
11137
11275
  hidden: true,
11138
11276
  size: 255,
11139
11277
  nullable: false
11140
11278
  }),
11141
- mimetype: useTextField7({
11279
+ mimetype: useTextField8({
11142
11280
  label: { en: "MIME Type", es: "Tipo MIME" },
11143
11281
  required: true,
11144
11282
  size: 100,
@@ -11154,14 +11292,14 @@ var init_storage_entity = __esm({
11154
11292
  meta: { sortable: true },
11155
11293
  displayProps: { format: "bytes" }
11156
11294
  }),
11157
- folder: useTextField7({
11295
+ folder: useTextField8({
11158
11296
  label: { en: "Folder", es: "Carpeta" },
11159
11297
  size: 100,
11160
11298
  nullable: true,
11161
11299
  index: true,
11162
11300
  meta: { searchable: true }
11163
11301
  }),
11164
- scope: useTextField7({
11302
+ scope: useTextField8({
11165
11303
  label: { en: "Storage Scope", es: "\xC1mbito de almacenamiento" },
11166
11304
  hidden: true,
11167
11305
  size: 50,
@@ -11172,7 +11310,7 @@ var init_storage_entity = __esm({
11172
11310
  es: "\xC1mbito de configuraci\xF3n de almacenamiento usado para este archivo"
11173
11311
  }
11174
11312
  }),
11175
- path: useTextField7({
11313
+ path: useTextField8({
11176
11314
  label: { en: "Full Path", es: "Ruta completa" },
11177
11315
  required: true,
11178
11316
  hidden: true,
@@ -11185,13 +11323,13 @@ var init_storage_entity = __esm({
11185
11323
  nullable: true,
11186
11324
  meta: { exportable: true, showInDisplay: false }
11187
11325
  }),
11188
- thumbnail_path: useTextField7({
11326
+ thumbnail_path: useTextField8({
11189
11327
  label: { en: "Thumbnail Path", es: "Ruta de miniatura" },
11190
11328
  size: 500,
11191
11329
  nullable: true,
11192
11330
  meta: { showInDisplay: false }
11193
11331
  }),
11194
- hash: useTextField7({
11332
+ hash: useTextField8({
11195
11333
  label: { en: "SHA256 Hash", es: "Hash SHA256" },
11196
11334
  hidden: true,
11197
11335
  size: 64,
@@ -11680,15 +11818,15 @@ var init_storage = __esm({
11680
11818
  routes: (ctx) => createStorageRoutes(ctx),
11681
11819
  // Import dinámico para evitar ciclos
11682
11820
  seed: async (ctx) => {
11683
- const { seed: seed5 } = await Promise.resolve().then(() => (init_storage_seed(), storage_seed_exports));
11684
- await seed5(ctx);
11821
+ const { seed: seed6 } = await Promise.resolve().then(() => (init_storage_seed(), storage_seed_exports));
11822
+ await seed6(ctx);
11685
11823
  }
11686
11824
  };
11687
11825
  }
11688
11826
  });
11689
11827
 
11690
11828
  // src/modules/users/users.entity.ts
11691
- import { useIdField as useIdField4, useSelectField as useSelectField9, useEmailField, usePasswordField, useTextField as useTextField8, useDatetimeField as useDatetimeField3, useCheckboxField as useCheckboxField4, useImageField as useImageField2, useNameField as useNameField2, useMetadataField as useMetadataField2, useDescriptionField as useDescriptionField2 } from "@gzl10/nexus-sdk/fields";
11829
+ 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";
11692
11830
  import { z as z3 } from "zod";
11693
11831
  var userEntity, roleEntity, userRoleEntity;
11694
11832
  var init_users_entity = __esm({
@@ -11751,7 +11889,7 @@ var init_users_entity = __esm({
11751
11889
  nullable: true,
11752
11890
  meta: { exportable: true, showInForm: false, showInDisplay: false }
11753
11891
  }),
11754
- consent_version: useTextField8({
11892
+ consent_version: useTextField9({
11755
11893
  label: { en: "Consent Version", es: "Versi\xF3n de consentimiento" },
11756
11894
  hidden: true,
11757
11895
  size: 20,
@@ -11762,7 +11900,7 @@ var init_users_entity = __esm({
11762
11900
  label: { en: "Marketing Opt-in", es: "Aceptar marketing" },
11763
11901
  meta: { exportable: true, showInForm: false, showInDisplay: false }
11764
11902
  }),
11765
- locale: useSelectField9({
11903
+ locale: useSelectField10({
11766
11904
  label: { en: "Language", es: "Idioma" },
11767
11905
  options: [
11768
11906
  { value: "es", label: { en: "Spanish", es: "Espa\xF1ol" } },
@@ -11772,13 +11910,13 @@ var init_users_entity = __esm({
11772
11910
  meta: { sortable: true },
11773
11911
  defaultValue: "en"
11774
11912
  }),
11775
- timezone: useSelectField9({
11913
+ timezone: useSelectField10({
11776
11914
  label: { en: "Timezone", es: "Zona horaria" },
11777
11915
  master: "timezones",
11778
11916
  meta: { sortable: true },
11779
11917
  defaultValue: "timezones:Europe/Madrid"
11780
11918
  }),
11781
- type: useSelectField9({
11919
+ type: useSelectField10({
11782
11920
  label: { en: "Type", es: "Tipo" },
11783
11921
  defaultValue: "human",
11784
11922
  options: [
@@ -11947,7 +12085,7 @@ var init_users_entity = __esm({
11947
12085
  expose: false,
11948
12086
  fields: {
11949
12087
  id: useIdField4(),
11950
- user_id: useSelectField9({
12088
+ user_id: useSelectField10({
11951
12089
  label: { en: "User", es: "Usuario" },
11952
12090
  required: true,
11953
12091
  table: "users",
@@ -11958,7 +12096,7 @@ var init_users_entity = __esm({
11958
12096
  labelField: "name",
11959
12097
  meta: { searchable: true }
11960
12098
  }),
11961
- role_id: useSelectField9({
12099
+ role_id: useSelectField10({
11962
12100
  label: { en: "Role", es: "Rol" },
11963
12101
  required: true,
11964
12102
  table: "roles",
@@ -12886,8 +13024,8 @@ var init_users = __esm({
12886
13024
  dependencies: ["logger"],
12887
13025
  // Import dinámico para evitar posibles ciclos
12888
13026
  seed: async (ctx) => {
12889
- const { seed: seed5 } = await Promise.resolve().then(() => (init_users_seed(), users_seed_exports));
12890
- await seed5(ctx);
13027
+ const { seed: seed6 } = await Promise.resolve().then(() => (init_users_seed(), users_seed_exports));
13028
+ await seed6(ctx);
12891
13029
  },
12892
13030
  init: (ctx) => {
12893
13031
  ctx.services.register("users", createUsersService(ctx));
@@ -12902,7 +13040,7 @@ var init_users = __esm({
12902
13040
  });
12903
13041
 
12904
13042
  // src/modules/auth/auth.entity.ts
12905
- import { useIdField as useIdField5, useTextField as useTextField9, useSelectField as useSelectField10, useDatetimeField as useDatetimeField4, useEmailField as useEmailField2, useMetadataField as useMetadataField3, useExpiresAtField } from "@gzl10/nexus-sdk/fields";
13043
+ 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";
12906
13044
  var refreshTokenEntity, authIdentitiesEntity;
12907
13045
  var init_auth_entity = __esm({
12908
13046
  "src/modules/auth/auth.entity.ts"() {
@@ -12917,7 +13055,7 @@ var init_auth_entity = __esm({
12917
13055
  expose: false,
12918
13056
  fields: {
12919
13057
  id: useIdField5(),
12920
- token: useTextField9({
13058
+ token: useTextField10({
12921
13059
  label: { en: "Token", es: "Token" },
12922
13060
  hidden: true,
12923
13061
  size: 255,
@@ -12944,14 +13082,14 @@ var init_auth_entity = __esm({
12944
13082
  nullable: true,
12945
13083
  meta: { sortable: true }
12946
13084
  }),
12947
- device_id: useTextField9({
13085
+ device_id: useTextField10({
12948
13086
  label: { en: "Device ID", es: "ID de dispositivo" },
12949
13087
  size: 64,
12950
13088
  index: true,
12951
13089
  nullable: true,
12952
13090
  meta: { searchable: true }
12953
13091
  }),
12954
- device_name: useTextField9({
13092
+ device_name: useTextField10({
12955
13093
  label: { en: "Device", es: "Dispositivo" },
12956
13094
  size: 100,
12957
13095
  nullable: true,
@@ -12983,7 +13121,7 @@ var init_auth_entity = __esm({
12983
13121
  order: 5,
12984
13122
  fields: {
12985
13123
  id: useIdField5(),
12986
- user_id: useSelectField10({
13124
+ user_id: useSelectField11({
12987
13125
  label: { en: "User", es: "Usuario" },
12988
13126
  table: "users",
12989
13127
  column: "id",
@@ -12995,7 +13133,7 @@ var init_auth_entity = __esm({
12995
13133
  labelField: "name",
12996
13134
  meta: { searchable: true }
12997
13135
  }),
12998
- provider: useTextField9({
13136
+ provider: useTextField10({
12999
13137
  label: { en: "Provider", es: "Proveedor" },
13000
13138
  required: true,
13001
13139
  size: 50,
@@ -13004,7 +13142,7 @@ var init_auth_entity = __esm({
13004
13142
  hint: { en: "e.g. pocketid, google, microsoft", es: "ej. pocketid, google, microsoft" },
13005
13143
  meta: { sortable: true, searchable: true }
13006
13144
  }),
13007
- provider_user_id: useTextField9({
13145
+ provider_user_id: useTextField10({
13008
13146
  label: { en: "Provider User ID", es: "ID de usuario del proveedor" },
13009
13147
  required: true,
13010
13148
  size: 255,
@@ -13299,7 +13437,7 @@ var init_auth_middleware = __esm({
13299
13437
  });
13300
13438
 
13301
13439
  // src/modules/auth/auth.pat.entity.ts
13302
- import { useIdField as useIdField6, useTextField as useTextField10, useSelectField as useSelectField11, useDatetimeField as useDatetimeField5, useExpiresAtField as useExpiresAtField2 } from "@gzl10/nexus-sdk/fields";
13440
+ import { useIdField as useIdField6, useTextField as useTextField11, useSelectField as useSelectField12, useDatetimeField as useDatetimeField5, useExpiresAtField as useExpiresAtField2 } from "@gzl10/nexus-sdk/fields";
13303
13441
  var personalTokenEntity;
13304
13442
  var init_auth_pat_entity = __esm({
13305
13443
  "src/modules/auth/auth.pat.entity.ts"() {
@@ -13316,7 +13454,7 @@ var init_auth_pat_entity = __esm({
13316
13454
  routePrefix: "/personal-tokens",
13317
13455
  fields: {
13318
13456
  id: useIdField6(),
13319
- user_id: useSelectField11({
13457
+ user_id: useSelectField12({
13320
13458
  label: { en: "User", es: "Usuario" },
13321
13459
  table: "users",
13322
13460
  column: "id",
@@ -13328,7 +13466,7 @@ var init_auth_pat_entity = __esm({
13328
13466
  labelField: "name",
13329
13467
  meta: { searchable: true }
13330
13468
  }),
13331
- name: useTextField10({
13469
+ name: useTextField11({
13332
13470
  label: { en: "Name", es: "Nombre" },
13333
13471
  required: true,
13334
13472
  size: 100,
@@ -13336,14 +13474,14 @@ var init_auth_pat_entity = __esm({
13336
13474
  hint: { en: "Descriptive name for this token", es: "Nombre descriptivo para este token" },
13337
13475
  meta: { searchable: true }
13338
13476
  }),
13339
- token_prefix: useTextField10({
13477
+ token_prefix: useTextField11({
13340
13478
  label: { en: "Token", es: "Token" },
13341
13479
  size: 20,
13342
13480
  disabled: true,
13343
13481
  nullable: false,
13344
13482
  hint: { en: "Partial token for identification", es: "Token parcial para identificaci\xF3n" }
13345
13483
  }),
13346
- token_hash: useTextField10({
13484
+ token_hash: useTextField11({
13347
13485
  label: { en: "Token Hash", es: "Hash del token" },
13348
13486
  size: 64,
13349
13487
  hidden: true,
@@ -13351,7 +13489,7 @@ var init_auth_pat_entity = __esm({
13351
13489
  unique: true,
13352
13490
  meta: { exportable: false }
13353
13491
  }),
13354
- scope: useSelectField11({
13492
+ scope: useSelectField12({
13355
13493
  label: { en: "Permission", es: "Permiso" },
13356
13494
  required: true,
13357
13495
  options: [
@@ -14940,8 +15078,8 @@ var init_auth = __esm({
14940
15078
  routePrefix: "/auth",
14941
15079
  // Import dinámico para evitar ciclos
14942
15080
  seed: async (ctx) => {
14943
- const { seed: seed5 } = await Promise.resolve().then(() => (init_auth_seed(), auth_seed_exports));
14944
- await seed5(ctx);
15081
+ const { seed: seed6 } = await Promise.resolve().then(() => (init_auth_seed(), auth_seed_exports));
15082
+ await seed6(ctx);
14945
15083
  },
14946
15084
  injectActions: [
14947
15085
  { target: { module: "users", entity: "users" }, action: impersonateAction }
@@ -15107,7 +15245,7 @@ var init_mail_service = __esm({
15107
15245
  });
15108
15246
 
15109
15247
  // src/modules/mail/mail.entity.ts
15110
- import { useIdField as useIdField7, useTextField as useTextField11, useSelectField as useSelectField12, 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";
15248
+ 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";
15111
15249
  import nodemailer2 from "nodemailer";
15112
15250
  async function getMailConfigFromDB(ctx) {
15113
15251
  const configService = ctx.services["config"];
@@ -15170,7 +15308,7 @@ var init_mail_entity = __esm({
15170
15308
  },
15171
15309
  fields: {
15172
15310
  id: useIdField7(),
15173
- host: useTextField11({
15311
+ host: useTextField12({
15174
15312
  label: { en: "SMTP Host", es: "Host SMTP" },
15175
15313
  size: 255,
15176
15314
  nullable: false,
@@ -15190,7 +15328,7 @@ var init_mail_entity = __esm({
15190
15328
  nullable: false,
15191
15329
  hint: { en: "Default: SMTP_FROM env var", es: "Por defecto: variable SMTP_FROM" }
15192
15330
  }),
15193
- auth_user: useTextField11({
15331
+ auth_user: useTextField12({
15194
15332
  label: { en: "Auth User", es: "Usuario de autenticaci\xF3n" },
15195
15333
  size: 255,
15196
15334
  nullable: true,
@@ -15222,12 +15360,12 @@ var init_mail_entity = __esm({
15222
15360
  required: true,
15223
15361
  validation: { format: "email" }
15224
15362
  }),
15225
- subject: useTextField11({
15363
+ subject: useTextField12({
15226
15364
  label: { en: "Subject", es: "Asunto" },
15227
15365
  required: true,
15228
15366
  validation: { min: 1, max: 255 }
15229
15367
  }),
15230
- title: useTextField11({
15368
+ title: useTextField12({
15231
15369
  label: { en: "Title", es: "T\xEDtulo" },
15232
15370
  hint: { en: "Large title in email header", es: "T\xEDtulo grande en la cabecera del correo" }
15233
15371
  }),
@@ -15371,20 +15509,20 @@ var init_mail_entity = __esm({
15371
15509
  nullable: false,
15372
15510
  meta: { sortable: true }
15373
15511
  }),
15374
- to: useTextField11({
15512
+ to: useTextField12({
15375
15513
  label: { en: "Recipient(s)", es: "Destinatario(s)" },
15376
15514
  size: 1e3,
15377
15515
  nullable: false,
15378
15516
  meta: { searchable: true }
15379
15517
  }),
15380
- subject: useTextField11({
15518
+ subject: useTextField12({
15381
15519
  label: { en: "Subject", es: "Asunto" },
15382
15520
  size: 255,
15383
15521
  nullable: false,
15384
15522
  meta: { searchable: true, sortable: true }
15385
15523
  }),
15386
15524
  status: {
15387
- ...useSelectField12({
15525
+ ...useSelectField13({
15388
15526
  label: { en: "Status", es: "Estado" },
15389
15527
  options: [
15390
15528
  { value: "pending", label: { en: "Pending", es: "Pendiente" } },
@@ -15398,7 +15536,7 @@ var init_mail_entity = __esm({
15398
15536
  }),
15399
15537
  validation: { enum: ["pending", "sent", "failed", "bounced"] }
15400
15538
  },
15401
- message_id: useTextField11({
15539
+ message_id: useTextField12({
15402
15540
  label: { en: "Message ID", es: "ID de mensaje" },
15403
15541
  hidden: true,
15404
15542
  size: 255,
@@ -15408,7 +15546,7 @@ var init_mail_entity = __esm({
15408
15546
  label: { en: "Error", es: "Error" },
15409
15547
  nullable: true
15410
15548
  }),
15411
- sent_by: useSelectField12({
15549
+ sent_by: useSelectField13({
15412
15550
  label: { en: "Sent by", es: "Enviado por" },
15413
15551
  table: "users",
15414
15552
  column: "id",
@@ -15531,8 +15669,8 @@ var init_mail = __esm({
15531
15669
  },
15532
15670
  // Import dinámico para evitar ciclos
15533
15671
  seed: async (ctx) => {
15534
- const { seed: seed5 } = await Promise.resolve().then(() => (init_mail_seed(), mail_seed_exports));
15535
- await seed5(ctx);
15672
+ const { seed: seed6 } = await Promise.resolve().then(() => (init_mail_seed(), mail_seed_exports));
15673
+ await seed6(ctx);
15536
15674
  }
15537
15675
  };
15538
15676
  }
@@ -16034,7 +16172,7 @@ var init_toggle_plugin_action = __esm({
16034
16172
  });
16035
16173
 
16036
16174
  // src/modules/plugins/plugins.entity.ts
16037
- import { useTextField as useTextField12, useSelectField as useSelectField13, useCheckboxField as useCheckboxField5 } from "@gzl10/nexus-sdk/fields";
16175
+ import { useTextField as useTextField13, useSelectField as useSelectField14, useCheckboxField as useCheckboxField5 } from "@gzl10/nexus-sdk/fields";
16038
16176
  import { OFFICIAL_PLUGINS } from "@gzl10/nexus-sdk";
16039
16177
  var allowPluginManagement, pluginsEntity;
16040
16178
  var init_plugins_entity = __esm({
@@ -16053,30 +16191,30 @@ var init_plugins_entity = __esm({
16053
16191
  routePrefix: "/",
16054
16192
  defaultSort: { field: "name", order: "asc" },
16055
16193
  fields: {
16056
- name: useTextField12({
16194
+ name: useTextField13({
16057
16195
  label: { en: "Name", es: "Nombre" },
16058
16196
  size: 50,
16059
16197
  nullable: false,
16060
16198
  meta: { sortable: true, searchable: true }
16061
16199
  }),
16062
- code: useTextField12({
16200
+ code: useTextField13({
16063
16201
  label: { en: "Code", es: "C\xF3digo" },
16064
16202
  size: 10,
16065
16203
  nullable: false,
16066
16204
  meta: { sortable: true }
16067
16205
  }),
16068
- label: useTextField12({
16206
+ label: useTextField13({
16069
16207
  label: { en: "Label", es: "Etiqueta" },
16070
16208
  size: 100,
16071
16209
  nullable: false,
16072
16210
  meta: { sortable: true }
16073
16211
  }),
16074
- version: useTextField12({
16212
+ version: useTextField13({
16075
16213
  label: { en: "Version", es: "Versi\xF3n" },
16076
16214
  size: 20,
16077
16215
  nullable: false
16078
16216
  }),
16079
- category: useSelectField13({
16217
+ category: useSelectField14({
16080
16218
  label: { en: "Category", es: "Categor\xEDa" },
16081
16219
  options: [
16082
16220
  { value: "content", label: { en: "Content", es: "Contenido" } },
@@ -16217,8 +16355,8 @@ var init_plugins = __esm({
16217
16355
  // src/modules/audit/audit.entity.ts
16218
16356
  import {
16219
16357
  useIdField as useIdField8,
16220
- useTextField as useTextField13,
16221
- useSelectField as useSelectField14,
16358
+ useTextField as useTextField14,
16359
+ useSelectField as useSelectField15,
16222
16360
  useTextareaField as useTextareaField4,
16223
16361
  useJsonField as useJsonField3,
16224
16362
  useDatetimeField as useDatetimeField7,
@@ -16241,7 +16379,7 @@ var init_audit_entity = __esm({
16241
16379
  fields: {
16242
16380
  id: useIdField8(),
16243
16381
  source: {
16244
- ...useTextField13({
16382
+ ...useTextField14({
16245
16383
  label: { en: "Source", es: "Origen" },
16246
16384
  size: 100,
16247
16385
  nullable: false,
@@ -16251,7 +16389,7 @@ var init_audit_entity = __esm({
16251
16389
  validation: { min: 1, max: 100 }
16252
16390
  },
16253
16391
  action: {
16254
- ...useTextField13({
16392
+ ...useTextField14({
16255
16393
  label: { en: "Action", es: "Acci\xF3n" },
16256
16394
  size: 100,
16257
16395
  nullable: false,
@@ -16260,7 +16398,7 @@ var init_audit_entity = __esm({
16260
16398
  }),
16261
16399
  validation: { min: 1, max: 100 }
16262
16400
  },
16263
- actor_id: useSelectField14({
16401
+ actor_id: useSelectField15({
16264
16402
  label: { en: "Actor", es: "Actor" },
16265
16403
  table: "users",
16266
16404
  column: "id",
@@ -16277,20 +16415,20 @@ var init_audit_entity = __esm({
16277
16415
  nullable: true,
16278
16416
  meta: { searchable: true }
16279
16417
  }),
16280
- resource_type: useTextField13({
16418
+ resource_type: useTextField14({
16281
16419
  label: { en: "Resource Type", es: "Tipo de recurso" },
16282
16420
  size: 100,
16283
16421
  nullable: true,
16284
16422
  index: true,
16285
16423
  meta: { searchable: true }
16286
16424
  }),
16287
- resource_id: useTextField13({
16425
+ resource_id: useTextField14({
16288
16426
  label: { en: "Resource ID", es: "ID del recurso" },
16289
16427
  size: 100,
16290
16428
  nullable: true,
16291
16429
  meta: { searchable: true }
16292
16430
  }),
16293
- ip_address: useTextField13({
16431
+ ip_address: useTextField14({
16294
16432
  label: { en: "IP Address", es: "Direcci\xF3n IP" },
16295
16433
  size: 45,
16296
16434
  nullable: true,
@@ -17225,33 +17363,10 @@ function buildMigrationSources() {
17225
17363
  sources.push({ id: "project", dir: getProjectMigrationsDir(), prefix: "" });
17226
17364
  return sources;
17227
17365
  }
17228
- function resolvePluginSource(source) {
17229
- if (!source.startsWith("plugin:")) return source;
17230
- const identifier = source.slice("plugin:".length);
17231
- if (/^[a-z]{3}$/.test(identifier)) {
17232
- for (const [name, plugin2] of moduleStore.plugins) {
17233
- if (plugin2.code === identifier) return `plugin:${name}`;
17234
- }
17235
- const available = [...moduleStore.plugins.values()].map((p) => p.code).sort().join(", ");
17236
- throw new CliError(
17237
- `Plugin code '${identifier}' not found`,
17238
- available ? `Available codes: ${available}` : "No plugins registered"
17239
- );
17240
- }
17241
- return `plugin:${normalizePluginName(identifier)}`;
17242
- }
17243
- function normalizeScope(raw) {
17244
- if (!raw) return void 0;
17245
- if (raw === "core" || raw === "project" || raw === "all") return raw;
17246
- const prefixed = raw.startsWith("plugin:") ? raw : `plugin:${raw}`;
17247
- return resolvePluginSource(prefixed);
17248
- }
17249
17366
  var init_migration_sources = __esm({
17250
17367
  "src/db/migration-sources.ts"() {
17251
17368
  "use strict";
17252
- init_shared();
17253
17369
  init_paths();
17254
- init_plugin_ops();
17255
17370
  init_module_store();
17256
17371
  }
17257
17372
  });
@@ -19574,15 +19689,10 @@ async function loadModulesForMigration() {
19574
19689
  }
19575
19690
  }
19576
19691
  }
19577
- async function handleCreate(name, options) {
19692
+ async function handleCreate(name) {
19578
19693
  initCli();
19579
19694
  await loadModulesForMigration();
19580
- let scope;
19581
- try {
19582
- scope = normalizeScope(options.source);
19583
- } catch (err) {
19584
- handleCliError(err);
19585
- }
19695
+ const scope = detectDefaultScope();
19586
19696
  const db3 = getDb();
19587
19697
  try {
19588
19698
  await ensureMigrationTables(db3);
@@ -19595,19 +19705,13 @@ async function handleCreate(name, options) {
19595
19705
  process.exit(0);
19596
19706
  }
19597
19707
  }
19598
- async function handleDev(name, options) {
19708
+ async function handleDev(name) {
19599
19709
  initCli();
19600
19710
  await loadModulesForMigration();
19601
- let scope;
19602
- try {
19603
- scope = normalizeScope(options.source);
19604
- } catch (err) {
19605
- handleCliError(err);
19606
- }
19607
19711
  const db3 = getDb();
19608
19712
  try {
19609
19713
  await ensureMigrationTables(db3);
19610
- await devMigration(name, scope);
19714
+ await devMigration(name);
19611
19715
  } catch (err) {
19612
19716
  console.error("Migration dev failed:", err);
19613
19717
  process.exit(1);
@@ -19669,17 +19773,9 @@ async function handleDeploy(options) {
19669
19773
  }
19670
19774
  }
19671
19775
  async function handleDown(options) {
19672
- if (!options?.source && !options?.name) {
19673
- handleCliError(new CliError("Specify -s <source> or --name <migration>", "Sources: core, project, plugin:<code|name>, or all"));
19674
- }
19675
19776
  initCli();
19676
19777
  await loadModulesForMigration();
19677
- let source;
19678
- try {
19679
- source = normalizeScope(options?.source);
19680
- } catch (err) {
19681
- handleCliError(err);
19682
- }
19778
+ const scope = detectDefaultScope();
19683
19779
  const db3 = getDb();
19684
19780
  try {
19685
19781
  await ensureMigrationTables(db3);
@@ -19687,8 +19783,8 @@ async function handleDown(options) {
19687
19783
  consola2.start(`Rolling back migration: ${options.name}`);
19688
19784
  await rollbackByName(options.name);
19689
19785
  } else {
19690
- const sourceId = scopeToSourceId(source);
19691
- consola2.start(source ? `Rolling back last batch [${source}]` : "Rolling back last batch");
19786
+ const sourceId = scopeToSourceId(scope);
19787
+ consola2.start(`Rolling back last batch [${scope}]`);
19692
19788
  await rollbackLastBatch(void 0, sourceId);
19693
19789
  }
19694
19790
  consola2.success("Rollback completed successfully");
@@ -19702,17 +19798,12 @@ async function handleDown(options) {
19702
19798
  }
19703
19799
  async function handleUndo(options) {
19704
19800
  if (process.env["NODE_ENV"] === "production") {
19705
- consola2.error("Cannot undo migrations in production");
19706
- process.exit(1);
19801
+ consola2.warn("Cannot undo migrations in production.");
19802
+ return;
19707
19803
  }
19708
19804
  initCli();
19709
19805
  await loadModulesForMigration();
19710
- let scope;
19711
- try {
19712
- scope = normalizeScope(options?.source);
19713
- } catch (err) {
19714
- handleCliError(err);
19715
- }
19806
+ const scope = detectDefaultScope();
19716
19807
  const sourceId = scopeToSourceId(scope);
19717
19808
  const db3 = getDb();
19718
19809
  try {
@@ -19721,7 +19812,7 @@ async function handleUndo(options) {
19721
19812
  if (sourceId) previewQuery.where({ source: sourceId });
19722
19813
  const target = await previewQuery.orderBy("executed_at", "desc").orderBy("batch", "desc").first();
19723
19814
  if (!target) {
19724
- consola2.info(scope ? `No completed migrations to undo [${scope}]` : "No completed migrations to undo");
19815
+ consola2.info(`No completed migrations to undo [${scope}]`);
19725
19816
  process.exit(0);
19726
19817
  }
19727
19818
  consola2.warn(`This will rollback AND DELETE migration: ${target.name}`);
@@ -19795,21 +19886,28 @@ async function handleStatus() {
19795
19886
  }
19796
19887
  async function handleReset(options) {
19797
19888
  if (process.env["NODE_ENV"] === "production") {
19798
- consola2.error("Cannot reset database in production");
19799
- process.exit(1);
19889
+ consola2.warn("Cannot reset database in production.");
19890
+ return;
19800
19891
  }
19801
19892
  initCli();
19802
19893
  await loadModulesForMigration();
19803
- let scope;
19804
- try {
19805
- scope = normalizeScope(options?.source);
19806
- } catch (err) {
19807
- handleCliError(err);
19808
- }
19894
+ const scope = detectDefaultScope();
19809
19895
  const sourceId = scopeToSourceId(scope);
19810
19896
  const db3 = getDb();
19811
19897
  try {
19812
- consola2.warn(scope ? `Resetting database [${scope}] \u2014 rollback all + re-run` : "Resetting database \u2014 rollback all + re-run");
19898
+ consola2.warn(`Resetting database [${scope}] \u2014 rollback all + re-run`);
19899
+ if (!options?.force) {
19900
+ const readline = await import("readline");
19901
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
19902
+ const answer = await new Promise((resolve) => {
19903
+ rl.question("Continue? (y/N) ", resolve);
19904
+ });
19905
+ rl.close();
19906
+ if (answer.toLowerCase() !== "y") {
19907
+ consola2.info("Aborted");
19908
+ process.exit(0);
19909
+ }
19910
+ }
19813
19911
  await ensureMigrationTables(db3);
19814
19912
  await resetDatabase(void 0, sourceId);
19815
19913
  consola2.success("Database reset complete");
@@ -19823,24 +19921,29 @@ async function handleReset(options) {
19823
19921
  }
19824
19922
  async function handleDrop(options) {
19825
19923
  if (process.env["NODE_ENV"] === "production") {
19826
- consola2.error("Cannot drop migrations in production");
19827
- process.exit(1);
19924
+ consola2.warn("Cannot drop migrations in production.");
19925
+ return;
19828
19926
  }
19829
19927
  initCli();
19830
19928
  await loadModulesForMigration();
19831
- let scope;
19832
- try {
19833
- scope = normalizeScope(options.source);
19834
- } catch (err) {
19835
- handleCliError(err);
19836
- }
19837
- if (scope === "all") {
19838
- handleCliError(new CliError("Cannot drop all sources", 'Use "nexus db wipe" to drop all tables'));
19839
- }
19929
+ const scope = detectDefaultScope();
19840
19930
  const sourceId = scopeToSourceId(scope);
19841
19931
  const db3 = getDb();
19842
19932
  try {
19843
19933
  await ensureMigrationTables(db3);
19934
+ consola2.warn(`This will DROP ALL migrations for source: ${sourceId}`);
19935
+ if (!options?.force) {
19936
+ const readline = await import("readline");
19937
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
19938
+ const answer = await new Promise((resolve) => {
19939
+ rl.question("Continue? (y/N) ", resolve);
19940
+ });
19941
+ rl.close();
19942
+ if (answer.toLowerCase() !== "y") {
19943
+ consola2.info("Aborted");
19944
+ process.exit(0);
19945
+ }
19946
+ }
19844
19947
  consola2.start(`Dropping all migrations for source: ${sourceId}`);
19845
19948
  await rollbackAll(db3, sourceId);
19846
19949
  consola2.success(`All migrations dropped for source: ${sourceId}`);
@@ -19864,7 +19967,6 @@ var init_migrate_commands = __esm({
19864
19967
  init_ensure_system_tables();
19865
19968
  init_migration_generator();
19866
19969
  init_migration_runner();
19867
- init_migration_sources();
19868
19970
  }
19869
19971
  });
19870
19972
 
@@ -19879,10 +19981,11 @@ __export(db_commands_exports, {
19879
19981
  import { spawn as spawn2 } from "child_process";
19880
19982
  import { isAbsolute as isAbsolute3, join as join15 } from "path";
19881
19983
  import { statSync as statSync2 } from "fs";
19984
+ import { consola as consola3 } from "consola";
19882
19985
  async function handleDbWipe(options) {
19883
19986
  if (process.env["NODE_ENV"] === "production") {
19884
- console.error("Cannot wipe database in production");
19885
- process.exit(1);
19987
+ consola3.warn("Cannot wipe database in production.");
19988
+ return;
19886
19989
  }
19887
19990
  initCli();
19888
19991
  const db3 = getDb();
@@ -20069,7 +20172,7 @@ __export(plugin_commands_exports, {
20069
20172
  import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
20070
20173
  import { join as join16 } from "path";
20071
20174
  import Table2 from "cli-table3";
20072
- import { consola as consola3 } from "consola";
20175
+ import { consola as consola4 } from "consola";
20073
20176
  import { OFFICIAL_PLUGINS as OFFICIAL_PLUGINS2 } from "@gzl10/nexus-sdk";
20074
20177
  function pluginLabel(name) {
20075
20178
  return shortPluginName(name).split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
@@ -20133,7 +20236,7 @@ async function handlePluginList(options = {}) {
20133
20236
  }
20134
20237
  console.log(table.toString());
20135
20238
  } else {
20136
- consola3.info("No plugins installed.");
20239
+ consola4.info("No plugins installed.");
20137
20240
  }
20138
20241
  const available = OFFICIAL_PLUGINS2.filter((name) => !installedNames.has(name));
20139
20242
  if (available.length > 0) {
@@ -20149,34 +20252,33 @@ async function handlePluginList(options = {}) {
20149
20252
  }
20150
20253
  async function handlePluginAdd(name, options) {
20151
20254
  if (process.env["NEXUS_ALLOW_PLUGIN_INSTALL"] === "false") {
20152
- consola3.error("Plugin installation is disabled (NEXUS_ALLOW_PLUGIN_INSTALL=false)");
20153
- process.exit(1);
20255
+ consola4.warn("Plugin installation is disabled (NEXUS_ALLOW_PLUGIN_INSTALL=false)");
20256
+ return;
20154
20257
  }
20155
20258
  initCli();
20156
20259
  const projectPath2 = getProjectPath();
20157
20260
  const discovered = await discoverPlugins(projectPath2);
20158
20261
  const fullName = resolvePluginName(name, discovered);
20159
20262
  try {
20160
- consola3.start(`Installing ${fullName}${options.version ? `@${options.version}` : ""}...`);
20263
+ consola4.start(`Installing ${fullName}${options.version ? `@${options.version}` : ""}...`);
20161
20264
  await installPlugin(fullName, { version: options.version });
20162
- consola3.success(`Plugin ${fullName} installed and enabled.`);
20265
+ consola4.success(`Plugin ${fullName} installed and enabled.`);
20163
20266
  } catch (err) {
20164
- consola3.error(`Failed to install plugin: ${err.message}`);
20165
- process.exit(1);
20267
+ consola4.error(`Failed to install plugin: ${err.message}`);
20166
20268
  }
20167
20269
  }
20168
20270
  async function handlePluginRemove(name, options = {}) {
20169
20271
  if (process.env["NEXUS_ALLOW_PLUGIN_INSTALL"] === "false") {
20170
- consola3.error("Plugin management is disabled (NEXUS_ALLOW_PLUGIN_INSTALL=false)");
20171
- process.exit(1);
20272
+ consola4.warn("Plugin management is disabled (NEXUS_ALLOW_PLUGIN_INSTALL=false)");
20273
+ return;
20172
20274
  }
20173
20275
  if (!name && !options.all) {
20174
- consola3.error("Provide a plugin name or use -a to remove all.");
20175
- process.exit(1);
20276
+ consola4.warn("Provide a plugin name or use -a to remove all.");
20277
+ return;
20176
20278
  }
20177
20279
  if (name && options.all) {
20178
- consola3.error("Cannot combine plugin name with -a flag.");
20179
- process.exit(1);
20280
+ consola4.warn("Cannot combine plugin name with -a flag.");
20281
+ return;
20180
20282
  }
20181
20283
  initCli();
20182
20284
  const projectPath2 = getProjectPath();
@@ -20185,7 +20287,7 @@ async function handlePluginRemove(name, options = {}) {
20185
20287
  const states = getAllPluginStates(projectPath2);
20186
20288
  const names = Object.keys(states);
20187
20289
  if (names.length === 0) {
20188
- consola3.info("No plugins installed.");
20290
+ consola4.info("No plugins installed.");
20189
20291
  return;
20190
20292
  }
20191
20293
  const table = new Table2({ head: ["Name", "Enabled"] });
@@ -20195,54 +20297,57 @@ async function handlePluginRemove(name, options = {}) {
20195
20297
  console.log("\n Plugins to remove:");
20196
20298
  console.log(table.toString());
20197
20299
  console.log(`
20198
- Tip: run "nexus migrate drop -s plugin:<name>" for each plugin first to drop their tables.`);
20199
- const confirmed2 = await consola3.prompt(
20300
+ Tip: run "nexus migrate drop" from each plugin directory first to drop their tables.`);
20301
+ const confirmed2 = await consola4.prompt(
20200
20302
  `Remove ALL ${names.length} plugins? This cannot be undone.`,
20201
20303
  { type: "confirm", initial: false }
20202
20304
  );
20203
20305
  if (!confirmed2 || typeof confirmed2 === "symbol") {
20204
- consola3.info("Aborted.");
20306
+ consola4.info("Aborted.");
20205
20307
  return;
20206
20308
  }
20207
20309
  for (const n of names) {
20208
20310
  try {
20209
- consola3.start(`Removing ${shortPluginName(n)}...`);
20311
+ consola4.start(`Removing ${shortPluginName(n)}...`);
20210
20312
  await uninstallPlugin(n);
20211
- consola3.success(`${shortPluginName(n)} removed.`);
20313
+ consola4.success(`${shortPluginName(n)} removed.`);
20212
20314
  } catch (err) {
20213
- consola3.error(`Failed to remove ${shortPluginName(n)}: ${err.message}`);
20315
+ consola4.error(`Failed to remove ${shortPluginName(n)}: ${err.message}`);
20214
20316
  }
20215
20317
  }
20216
20318
  return;
20217
20319
  }
20218
20320
  const fullName = resolvePluginName(name, discovered);
20219
20321
  const short = shortPluginName(fullName);
20220
- const confirmed = await consola3.prompt(
20322
+ if (!isPackageInstalled(fullName) && !getPluginState(fullName)) {
20323
+ consola4.warn(`Plugin "${short}" is not installed.`);
20324
+ return;
20325
+ }
20326
+ const confirmed = await consola4.prompt(
20221
20327
  `Remove plugin "${short}"? This will uninstall the dependency.
20222
- Tip: run "nexus migrate drop -s plugin:${fullName}" first to drop its tables.`,
20328
+ Tip: run "nexus migrate drop" from the plugin directory first to drop its tables.`,
20223
20329
  { type: "confirm", initial: false }
20224
20330
  );
20225
20331
  if (!confirmed || typeof confirmed === "symbol") {
20226
- consola3.info("Aborted.");
20332
+ consola4.info("Aborted.");
20227
20333
  return;
20228
20334
  }
20229
20335
  try {
20230
- consola3.start(`Removing ${fullName}...`);
20336
+ consola4.start(`Removing ${fullName}...`);
20231
20337
  await uninstallPlugin(fullName);
20232
- consola3.success(`Plugin ${short} removed.`);
20338
+ consola4.success(`Plugin ${short} removed.`);
20233
20339
  } catch (err) {
20234
- consola3.error(`Failed to remove plugin: ${err.message}`);
20235
- process.exit(1);
20340
+ consola4.error(`Failed to remove plugin: ${err.message}`);
20236
20341
  }
20237
20342
  }
20238
20343
  async function handlePluginEnable(name, options = {}) {
20239
20344
  if (!name && !options.all) {
20240
- consola3.error("Provide a plugin name or use -a to enable all.");
20241
- process.exit(1);
20345
+ consola4.warn("Provide a plugin name or use -a to enable all.");
20346
+ return;
20242
20347
  }
20243
20348
  if (name && options.all) {
20244
- consola3.error("Cannot combine plugin name with -a flag.");
20245
- process.exit(1);
20349
+ consola4.warn("Cannot combine plugin name with -a flag.");
20350
+ return;
20246
20351
  }
20247
20352
  initCli();
20248
20353
  const projectPath2 = getProjectPath();
@@ -20250,34 +20355,33 @@ async function handlePluginEnable(name, options = {}) {
20250
20355
  const states = getAllPluginStates(projectPath2);
20251
20356
  const disabled = Object.entries(states).filter(([, s]) => !s.enabled);
20252
20357
  if (disabled.length === 0) {
20253
- consola3.info("All plugins are already enabled.");
20358
+ consola4.info("All plugins are already enabled.");
20254
20359
  return;
20255
20360
  }
20256
20361
  for (const [n] of disabled) {
20257
20362
  enablePlugin(n, projectPath2);
20258
- consola3.success(`${shortPluginName(n)} enabled.`);
20363
+ consola4.success(`${shortPluginName(n)} enabled.`);
20259
20364
  }
20260
- consola3.info("Restart server to apply.");
20365
+ consola4.info("Restart server to apply.");
20261
20366
  return;
20262
20367
  }
20263
20368
  const discovered = await discoverPlugins(projectPath2);
20264
20369
  const fullName = resolvePluginName(name, discovered);
20265
20370
  try {
20266
20371
  enablePlugin(fullName);
20267
- consola3.success(`Plugin ${shortPluginName(fullName)} enabled. Restart server to apply.`);
20372
+ consola4.success(`Plugin ${shortPluginName(fullName)} enabled. Restart server to apply.`);
20268
20373
  } catch (err) {
20269
- consola3.error(err.message);
20270
- process.exit(1);
20374
+ consola4.error(err.message);
20271
20375
  }
20272
20376
  }
20273
20377
  async function handlePluginDisable(name, options = {}) {
20274
20378
  if (!name && !options.all) {
20275
- consola3.error("Provide a plugin name or use -a to disable all.");
20276
- process.exit(1);
20379
+ consola4.warn("Provide a plugin name or use -a to disable all.");
20380
+ return;
20277
20381
  }
20278
20382
  if (name && options.all) {
20279
- consola3.error("Cannot combine plugin name with -a flag.");
20280
- process.exit(1);
20383
+ consola4.warn("Cannot combine plugin name with -a flag.");
20384
+ return;
20281
20385
  }
20282
20386
  initCli();
20283
20387
  const projectPath2 = getProjectPath();
@@ -20285,24 +20389,23 @@ async function handlePluginDisable(name, options = {}) {
20285
20389
  const states = getAllPluginStates(projectPath2);
20286
20390
  const enabled = Object.entries(states).filter(([, s]) => s.enabled);
20287
20391
  if (enabled.length === 0) {
20288
- consola3.info("All plugins are already disabled.");
20392
+ consola4.info("All plugins are already disabled.");
20289
20393
  return;
20290
20394
  }
20291
20395
  for (const [n] of enabled) {
20292
20396
  disablePlugin(n, projectPath2);
20293
- consola3.success(`${shortPluginName(n)} disabled.`);
20397
+ consola4.success(`${shortPluginName(n)} disabled.`);
20294
20398
  }
20295
- consola3.info("Restart server to apply.");
20399
+ consola4.info("Restart server to apply.");
20296
20400
  return;
20297
20401
  }
20298
20402
  const discovered = await discoverPlugins(projectPath2);
20299
20403
  const fullName = resolvePluginName(name, discovered);
20300
20404
  try {
20301
20405
  disablePlugin(fullName);
20302
- consola3.success(`Plugin ${shortPluginName(fullName)} disabled. Restart server to apply.`);
20406
+ consola4.success(`Plugin ${shortPluginName(fullName)} disabled. Restart server to apply.`);
20303
20407
  } catch (err) {
20304
- consola3.error(err.message);
20305
- process.exit(1);
20408
+ consola4.error(err.message);
20306
20409
  }
20307
20410
  }
20308
20411
  async function handlePluginInfo(name) {
@@ -20313,11 +20416,11 @@ async function handlePluginInfo(name) {
20313
20416
  const manifest = discovered.find((p) => p.name === fullName);
20314
20417
  const state = getPluginState(fullName, projectPath2);
20315
20418
  if (!manifest && !state) {
20316
- consola3.error(`Plugin ${fullName} not found (not in package.json nor nexus.plugins.json)`);
20317
- process.exit(1);
20419
+ consola4.warn(`Plugin "${shortPluginName(fullName)}" not found.`);
20420
+ return;
20318
20421
  }
20319
20422
  console.log("");
20320
- consola3.info(`Plugin: ${fullName}`);
20423
+ consola4.info(`Plugin: ${fullName}`);
20321
20424
  if (manifest) {
20322
20425
  console.log(` Code: ${manifest.code}`);
20323
20426
  console.log(` Version: ${manifest.version}`);
@@ -20372,9 +20475,9 @@ async function handleSyncCommands(options) {
20372
20475
  const sourceDir = join17(getLibPath(), "claude-commands");
20373
20476
  const targetDir = join17(homedir(), ".claude", "commands");
20374
20477
  if (!existsSync13(sourceDir)) {
20375
- logger2.error(`Commands source not found: ${sourceDir}`);
20478
+ logger2.warn(`Commands source not found: ${sourceDir}`);
20376
20479
  logger2.info("Make sure @gzl10/nexus-backend is properly installed.");
20377
- process.exit(1);
20480
+ return;
20378
20481
  }
20379
20482
  if (!existsSync13(targetDir)) {
20380
20483
  if (options.dryRun) {
@@ -20440,6 +20543,137 @@ var init_sync_commands = __esm({
20440
20543
  }
20441
20544
  });
20442
20545
 
20546
+ // src/cli/seed-commands.ts
20547
+ var seed_commands_exports = {};
20548
+ __export(seed_commands_exports, {
20549
+ handleSeedExport: () => handleSeedExport,
20550
+ importSeedFiles: () => importSeedFiles
20551
+ });
20552
+ import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4, readdirSync as readdirSync3, readFileSync as readFileSync11 } from "fs";
20553
+ import { join as join18, basename as basename5 } from "path";
20554
+ import { consola as consola5 } from "consola";
20555
+ function deserializeJsonFields(record, fields) {
20556
+ const result = { ...record };
20557
+ for (const [name, field] of Object.entries(fields)) {
20558
+ if (field.db?.type === "json" && typeof result[name] === "string") {
20559
+ try {
20560
+ result[name] = JSON.parse(result[name]);
20561
+ } catch {
20562
+ }
20563
+ }
20564
+ }
20565
+ return result;
20566
+ }
20567
+ function serializeJsonFields(record, fields) {
20568
+ const result = { ...record };
20569
+ for (const [name, field] of Object.entries(fields)) {
20570
+ if (field.db?.type === "json" && typeof result[name] === "object" && result[name] !== null) {
20571
+ result[name] = JSON.stringify(result[name]);
20572
+ }
20573
+ }
20574
+ return result;
20575
+ }
20576
+ async function handleSeedExport(entity) {
20577
+ initCli();
20578
+ await loadModulesForMigration();
20579
+ const db3 = getDb();
20580
+ try {
20581
+ const modules = getOrderedModules();
20582
+ const seedDir = join18(getProjectPath(), "data", "seeds");
20583
+ const seedableEntities = [];
20584
+ for (const mod of modules) {
20585
+ for (const def of mod.definitions ?? []) {
20586
+ if (!("seedable" in def) || !def.seedable) continue;
20587
+ if (entity && def.table !== entity) continue;
20588
+ seedableEntities.push({
20589
+ module: mod.name,
20590
+ table: def.table,
20591
+ fields: def.fields
20592
+ });
20593
+ }
20594
+ }
20595
+ if (seedableEntities.length === 0) {
20596
+ if (entity) {
20597
+ consola5.warn(`No seedable entity found with table "${entity}"`);
20598
+ } else {
20599
+ consola5.warn("No seedable entities found");
20600
+ }
20601
+ return;
20602
+ }
20603
+ if (!existsSync14(seedDir)) {
20604
+ mkdirSync7(seedDir, { recursive: true });
20605
+ }
20606
+ for (const { module: modName, table, fields } of seedableEntities) {
20607
+ const rows = await db3(table).orderBy("id");
20608
+ if (rows.length === 0) {
20609
+ consola5.info(`${table}: no records, skipping`);
20610
+ continue;
20611
+ }
20612
+ const exported = rows.map(
20613
+ (row) => deserializeJsonFields(row, fields)
20614
+ );
20615
+ const filePath = join18(seedDir, `${table}.json`);
20616
+ writeFileSync4(filePath, JSON.stringify(exported, null, 2) + "\n", "utf-8");
20617
+ consola5.success(`${table}: exported ${rows.length} records to data/seeds/${table}.json (module: ${modName})`);
20618
+ }
20619
+ } catch (err) {
20620
+ consola5.error("Seed export failed:", err);
20621
+ } finally {
20622
+ await db3.destroy();
20623
+ process.exit(0);
20624
+ }
20625
+ }
20626
+ async function importSeedFiles(db3, modules, logger3) {
20627
+ const seedDir = join18(getProjectPath(), "data", "seeds");
20628
+ if (!existsSync14(seedDir)) return;
20629
+ const files = readdirSync3(seedDir).filter((f) => f.endsWith(".json"));
20630
+ if (files.length === 0) return;
20631
+ const seedableDefs = /* @__PURE__ */ new Map();
20632
+ for (const mod of modules) {
20633
+ for (const rawDef of mod.definitions ?? []) {
20634
+ const def = rawDef;
20635
+ if (!def["seedable"] || !def["table"] || !def["fields"]) continue;
20636
+ seedableDefs.set(
20637
+ def["table"],
20638
+ { fields: def["fields"], module: mod.name }
20639
+ );
20640
+ }
20641
+ }
20642
+ for (const file of files) {
20643
+ const table = basename5(file, ".json");
20644
+ const defInfo = seedableDefs.get(table);
20645
+ if (!defInfo) {
20646
+ logger3.debug(`data/seeds/${file}: skipped (entity "${table}" is not seedable)`);
20647
+ continue;
20648
+ }
20649
+ const filePath = join18(seedDir, file);
20650
+ const raw = readFileSync11(filePath, "utf-8");
20651
+ let records;
20652
+ try {
20653
+ records = JSON.parse(raw);
20654
+ } catch {
20655
+ logger3.info(`data/seeds/${file}: skipped (invalid JSON)`);
20656
+ continue;
20657
+ }
20658
+ if (!Array.isArray(records) || records.length === 0) continue;
20659
+ const rows = records.map((r) => serializeJsonFields(r, defInfo.fields));
20660
+ for (const row of rows) {
20661
+ await db3(table).insert(row).onConflict("id").merge();
20662
+ }
20663
+ logger3.info(`Seeded ${rows.length} records into ${table} from data/seeds/${file}`);
20664
+ }
20665
+ }
20666
+ var init_seed_commands = __esm({
20667
+ "src/cli/seed-commands.ts"() {
20668
+ "use strict";
20669
+ init_engine();
20670
+ init_paths();
20671
+ init_connection();
20672
+ init_shared();
20673
+ init_migrate_commands();
20674
+ }
20675
+ });
20676
+
20443
20677
  // src/env-loader.ts
20444
20678
  import { existsSync } from "fs";
20445
20679
  import { join, dirname } from "path";
@@ -20460,12 +20694,12 @@ if (!nodeEnv || nodeEnv === "development") {
20460
20694
  }
20461
20695
 
20462
20696
  // src/cli.ts
20463
- import { readFileSync as readFileSync11 } from "fs";
20697
+ import { readFileSync as readFileSync12 } from "fs";
20464
20698
  import { fileURLToPath as fileURLToPath3 } from "url";
20465
- import { dirname as dirname8, join as join18 } from "path";
20699
+ import { dirname as dirname8, join as join19 } from "path";
20466
20700
  import { Command } from "commander";
20467
20701
  var __dirname2 = dirname8(fileURLToPath3(import.meta.url));
20468
- var pkg2 = JSON.parse(readFileSync11(join18(__dirname2, "..", "package.json"), "utf-8"));
20702
+ var pkg2 = JSON.parse(readFileSync12(join19(__dirname2, "..", "package.json"), "utf-8"));
20469
20703
  var program = new Command();
20470
20704
  program.name("nexus").description("Nexus Backend CLI").version(pkg2.version);
20471
20705
  program.command("info").description("Show Nexus environment, database, plugins, and paths").option("--json", "Output as JSON").action(async (options) => {
@@ -20473,13 +20707,13 @@ program.command("info").description("Show Nexus environment, database, plugins,
20473
20707
  await handleInfo2(options);
20474
20708
  });
20475
20709
  var migrate = program.command("migrate").description("Database migration management");
20476
- migrate.command("create <name>").description("Generate migration by comparing entities vs current schema").option("-s, --source <scope>", "Migration scope: core, project, plugin:<code|name>, or all", "core").action(async (name, options) => {
20710
+ migrate.command("create <name>").description("Generate migration by comparing entities vs current schema (scope auto-detected from CWD)").action(async (name) => {
20477
20711
  const { handleCreate: handleCreate2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20478
- await handleCreate2(name, options);
20712
+ await handleCreate2(name);
20479
20713
  });
20480
- migrate.command("dev [name]").description('Generate and apply migration automatically (auto-detects plugin scope). Name defaults to "auto" if omitted').option("-s, --source <scope>", "Override scope: project, plugin:<code|name>").action(async (name, options) => {
20714
+ migrate.command("dev [name]").description('Generate and apply migration automatically (scope auto-detected from CWD). Name defaults to "auto" if omitted').action(async (name) => {
20481
20715
  const { handleDev: handleDev2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20482
- await handleDev2(name, options);
20716
+ await handleDev2(name);
20483
20717
  });
20484
20718
  migrate.command("up").description("Run all pending migrations").action(async () => {
20485
20719
  const { handleUp: handleUp2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
@@ -20489,11 +20723,11 @@ migrate.command("deploy").description("Apply pending migrations (production-safe
20489
20723
  const { handleDeploy: handleDeploy2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20490
20724
  await handleDeploy2(options);
20491
20725
  });
20492
- migrate.command("down").description("Rollback last batch of migrations (or a specific migration with --name)").option("--name <migration_name>", "Rollback a specific migration by name").option("-s, --source <scope>", "Filter by source: core, project, plugin:<code|name>").action(async (options) => {
20726
+ migrate.command("down").description("Rollback last batch of migrations (scope auto-detected from CWD, or specific migration with --name)").option("--name <migration_name>", "Rollback a specific migration by name").action(async (options) => {
20493
20727
  const { handleDown: handleDown2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20494
20728
  await handleDown2(options);
20495
20729
  });
20496
- migrate.command("undo").description("Rollback last migration AND delete its file (DEV ONLY)").requiredOption("-s, --source <scope>", "Source: core, project, plugin:<code|name>, or all").option("--force", "Skip confirmation prompt").action(async (options) => {
20730
+ migrate.command("undo").description("Rollback last migration AND delete its file (DEV ONLY, scope auto-detected from CWD)").option("--force", "Skip confirmation prompt").action(async (options) => {
20497
20731
  const { handleUndo: handleUndo2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20498
20732
  await handleUndo2(options);
20499
20733
  });
@@ -20501,11 +20735,11 @@ migrate.command("status").description("Show migration status and schema drift").
20501
20735
  const { handleStatus: handleStatus2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20502
20736
  await handleStatus2();
20503
20737
  });
20504
- migrate.command("reset").description("Rollback all migrations and re-run (DEV ONLY)").requiredOption("-s, --source <scope>", "Source: core, project, plugin:<code|name>, or all").action(async (options) => {
20738
+ migrate.command("reset").description("Rollback all migrations and re-run (DEV ONLY, scope auto-detected from CWD)").option("--force", "Skip confirmation prompt").action(async (options) => {
20505
20739
  const { handleReset: handleReset2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20506
20740
  await handleReset2(options);
20507
20741
  });
20508
- migrate.command("drop").description("Rollback ALL batches of a source and remove records (DEV ONLY)").requiredOption("-s, --source <scope>", "Source: core, project, or plugin:<code|name>").action(async (options) => {
20742
+ migrate.command("drop").description("Rollback ALL batches of a source and remove records (DEV ONLY, scope auto-detected from CWD)").option("--force", "Skip confirmation prompt").action(async (options) => {
20509
20743
  const { handleDrop: handleDrop2 } = await Promise.resolve().then(() => (init_migrate_commands(), migrate_commands_exports));
20510
20744
  await handleDrop2(options);
20511
20745
  });
@@ -20551,5 +20785,10 @@ program.command("sync:commands").description("Sync Nexus Claude Code commands to
20551
20785
  const { handleSyncCommands: handleSyncCommands2 } = await Promise.resolve().then(() => (init_sync_commands(), sync_commands_exports));
20552
20786
  await handleSyncCommands2(options);
20553
20787
  });
20788
+ var seed5 = program.command("seed").description("Seed data management");
20789
+ seed5.command("export [entity]").description("Export seedable entity data from DB to data/seeds/ JSONs").action(async (entity) => {
20790
+ const { handleSeedExport: handleSeedExport2 } = await Promise.resolve().then(() => (init_seed_commands(), seed_commands_exports));
20791
+ await handleSeedExport2(entity);
20792
+ });
20554
20793
  program.parse();
20555
20794
  //# sourceMappingURL=cli.js.map