@gzl10/nexus-sdk 0.11.1 → 0.12.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/index.d.ts +163 -31
- package/package.json +5 -13
- package/README.md +0 -321
package/dist/index.d.ts
CHANGED
|
@@ -114,7 +114,7 @@ type DbType = 'string' | 'text' | 'integer' | 'decimal' | 'boolean' | 'date' | '
|
|
|
114
114
|
/**
|
|
115
115
|
* Tipos de input en UI
|
|
116
116
|
*/
|
|
117
|
-
type InputType = 'text' | 'email' | 'password' | 'url' | 'tel' | 'number' | 'decimal' | 'textarea' | 'markdown' | 'select' | 'multiselect' | 'tags' | 'checkbox' | 'switch' | 'date' | 'datetime' | 'file' | 'fileArray' | 'image' | 'imageArray' | 'hidden';
|
|
117
|
+
type InputType = 'text' | 'email' | 'password' | 'url' | 'tel' | 'number' | 'decimal' | 'textarea' | 'markdown' | 'json' | 'select' | 'multiselect' | 'tags' | 'checkbox' | 'switch' | 'date' | 'datetime' | 'file' | 'fileArray' | 'image' | 'imageArray' | 'hidden';
|
|
118
118
|
/**
|
|
119
119
|
* Configuración de base de datos para un campo
|
|
120
120
|
*/
|
|
@@ -159,6 +159,7 @@ interface FieldOptions {
|
|
|
159
159
|
value: string;
|
|
160
160
|
label: string;
|
|
161
161
|
}>;
|
|
162
|
+
allowCreate?: boolean;
|
|
162
163
|
}
|
|
163
164
|
/**
|
|
164
165
|
* Restricciones de acceso CASL para un campo
|
|
@@ -214,7 +215,7 @@ interface FieldDefinition {
|
|
|
214
215
|
hint?: string;
|
|
215
216
|
hidden?: boolean;
|
|
216
217
|
disabled?: boolean;
|
|
217
|
-
db
|
|
218
|
+
db?: FieldDbConfig;
|
|
218
219
|
relation?: FieldRelation;
|
|
219
220
|
validation?: FieldValidationConfig;
|
|
220
221
|
options?: FieldOptions;
|
|
@@ -279,6 +280,63 @@ interface EntityCaslConfig {
|
|
|
279
280
|
*/
|
|
280
281
|
sensitiveFields?: string[];
|
|
281
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Action vinculada a un registro de la entidad
|
|
285
|
+
* Define operaciones que actúan sobre registros existentes
|
|
286
|
+
*
|
|
287
|
+
* Ruta generada: GET|POST /{entityRoutePrefix}/{key}/:id
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```typescript
|
|
291
|
+
* actions: [{
|
|
292
|
+
* key: 'download',
|
|
293
|
+
* label: 'Download File',
|
|
294
|
+
* icon: 'mdi:download',
|
|
295
|
+
* method: 'GET',
|
|
296
|
+
* select: ['id', 'filename', 'mimetype'],
|
|
297
|
+
* handler: async (ctx, input, _req, res) => {
|
|
298
|
+
* const { _record: file, _authUserId } = input
|
|
299
|
+
* // file y _authUserId vienen inyectados automáticamente
|
|
300
|
+
* }
|
|
301
|
+
* }]
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
interface EntityAction {
|
|
305
|
+
/** Key única para la ruta (ej: 'download' → /download/:id) */
|
|
306
|
+
key: string;
|
|
307
|
+
/** Label para UI */
|
|
308
|
+
label: string;
|
|
309
|
+
/** Icono Iconify (default: 'mdi:play') */
|
|
310
|
+
icon?: string;
|
|
311
|
+
/** Método HTTP (default: 'POST') */
|
|
312
|
+
method?: 'GET' | 'POST';
|
|
313
|
+
/** Campos a seleccionar del registro (default: todos) */
|
|
314
|
+
select?: string[];
|
|
315
|
+
/** Schema de validación del body (opcional) */
|
|
316
|
+
inputSchema?: ValidationSchema;
|
|
317
|
+
/** Schema del output (documentación) */
|
|
318
|
+
outputSchema?: ValidationSchema;
|
|
319
|
+
/** Middleware custom (ej: multer) */
|
|
320
|
+
middleware?: (ctx: ModuleContext) => RequestHandler | RequestHandler[];
|
|
321
|
+
/**
|
|
322
|
+
* Handler - recibe _record y _authUserId automáticamente
|
|
323
|
+
* @param ctx - Contexto del módulo
|
|
324
|
+
* @param input - Body validado + _record + _authUserId
|
|
325
|
+
* @param req - Express Request
|
|
326
|
+
* @param res - Express Response (para streams, headers custom)
|
|
327
|
+
*/
|
|
328
|
+
handler: (ctx: ModuleContext, input: unknown, req?: Request, res?: Response) => Promise<unknown>;
|
|
329
|
+
/**
|
|
330
|
+
* Permisos CASL específicos para esta action
|
|
331
|
+
* Si no se define, hereda los permisos de la entidad padre
|
|
332
|
+
*/
|
|
333
|
+
casl?: {
|
|
334
|
+
/** Action CASL (default: 'execute') */
|
|
335
|
+
action?: string;
|
|
336
|
+
/** Conditions adicionales */
|
|
337
|
+
conditions?: Record<string, unknown>;
|
|
338
|
+
};
|
|
339
|
+
}
|
|
282
340
|
/**
|
|
283
341
|
* Propiedades base compartidas por todas las EntityDefinition
|
|
284
342
|
*/
|
|
@@ -293,6 +351,8 @@ interface BaseEntityDefinition {
|
|
|
293
351
|
casl?: EntityCaslConfig;
|
|
294
352
|
/** Prefijo de ruta para montar (default: inferido de table) */
|
|
295
353
|
routePrefix?: string;
|
|
354
|
+
/** Orden de visualización en UI (menor = primero, default: 999) */
|
|
355
|
+
order?: number;
|
|
296
356
|
}
|
|
297
357
|
/**
|
|
298
358
|
* Entidad de colección - CRUD completo (users, posts, orders)
|
|
@@ -310,6 +370,8 @@ interface CollectionEntityDefinition extends BaseEntityDefinition {
|
|
|
310
370
|
indexes?: EntityIndex[];
|
|
311
371
|
/** Usar deleted_at en vez de DELETE físico */
|
|
312
372
|
softDelete?: boolean;
|
|
373
|
+
/** Actions vinculadas a registros de esta entidad */
|
|
374
|
+
actions?: EntityAction[];
|
|
313
375
|
}
|
|
314
376
|
/**
|
|
315
377
|
* Entidad singleton - Un solo registro en tabla compartida sys_settings
|
|
@@ -334,6 +396,8 @@ interface SingleEntityDefinition {
|
|
|
334
396
|
casl?: EntityCaslConfig;
|
|
335
397
|
/** Prefijo de ruta para montar (default: inferido de key) */
|
|
336
398
|
routePrefix?: string;
|
|
399
|
+
/** Actions vinculadas a esta entidad single */
|
|
400
|
+
actions?: EntityAction[];
|
|
337
401
|
}
|
|
338
402
|
/**
|
|
339
403
|
* Entidad de referencia - Catálogos con CRUD admin (countries, currencies)
|
|
@@ -370,23 +434,43 @@ interface EventEntityDefinition extends BaseEntityDefinition {
|
|
|
370
434
|
}
|
|
371
435
|
/**
|
|
372
436
|
* Entidad de acción - Comandos/operaciones sin persistencia
|
|
437
|
+
* Para actions que operan sobre registros existentes, usar EntityAction en la entidad padre
|
|
373
438
|
*/
|
|
374
439
|
interface ActionEntityDefinition {
|
|
375
440
|
type: 'action';
|
|
376
441
|
/** Nombre para mostrar en UI */
|
|
377
442
|
label: string;
|
|
443
|
+
/** Icono Iconify para UI (default: 'mdi:play') */
|
|
444
|
+
icon?: string;
|
|
378
445
|
/** Solo campos de formulario para input, sin BD */
|
|
379
446
|
fields: Record<string, FieldDefinition>;
|
|
380
447
|
/** Schema Zod de input (se valida antes de ejecutar) */
|
|
381
448
|
inputSchema?: ValidationSchema;
|
|
382
449
|
/** Schema Zod de output (documenta respuesta) */
|
|
383
450
|
outputSchema?: ValidationSchema;
|
|
384
|
-
/**
|
|
385
|
-
|
|
451
|
+
/** Método HTTP (default: POST) */
|
|
452
|
+
method?: 'GET' | 'POST';
|
|
453
|
+
/**
|
|
454
|
+
* Middleware a aplicar antes del handler (ej: multer para uploads)
|
|
455
|
+
* Puede retornar un middleware o un array de middlewares
|
|
456
|
+
*/
|
|
457
|
+
middleware?: (ctx: ModuleContext) => RequestHandler | RequestHandler[];
|
|
458
|
+
/**
|
|
459
|
+
* Handler que ejecuta la acción
|
|
460
|
+
* @param ctx - Contexto del módulo
|
|
461
|
+
* @param input - Datos del body. Incluye _authUserId si hay usuario autenticado.
|
|
462
|
+
* @param req - Request de Express (opcional, para acceder a req.file, etc.)
|
|
463
|
+
* @param res - Response de Express (opcional, para streams, headers custom, etc.)
|
|
464
|
+
*/
|
|
465
|
+
handler?: (ctx: ModuleContext, input: unknown, req?: Request, res?: Response) => Promise<unknown>;
|
|
466
|
+
/** HTTP status code para respuesta exitosa (default: 200, usar 201 para creación) */
|
|
467
|
+
successStatus?: number;
|
|
386
468
|
/** Autorización CASL */
|
|
387
469
|
casl?: EntityCaslConfig;
|
|
388
470
|
/** Prefijo de ruta para montar */
|
|
389
471
|
routePrefix?: string;
|
|
472
|
+
/** Orden de visualización en UI (menor = primero, default: 999) */
|
|
473
|
+
order?: number;
|
|
390
474
|
}
|
|
391
475
|
/**
|
|
392
476
|
* Entidad externa - Datos de APIs externas (stripe_customers, github_repos)
|
|
@@ -422,6 +506,8 @@ interface ExternalEntityDefinition {
|
|
|
422
506
|
casl?: EntityCaslConfig;
|
|
423
507
|
/** Prefijo de ruta para montar */
|
|
424
508
|
routePrefix?: string;
|
|
509
|
+
/** Orden de visualización en UI (menor = primero, default: 999) */
|
|
510
|
+
order?: number;
|
|
425
511
|
}
|
|
426
512
|
/**
|
|
427
513
|
* Entidad virtual - Orquestación de múltiples fuentes (unified_customers)
|
|
@@ -443,6 +529,8 @@ interface VirtualEntityDefinition {
|
|
|
443
529
|
casl?: EntityCaslConfig;
|
|
444
530
|
/** Prefijo de ruta para montar */
|
|
445
531
|
routePrefix?: string;
|
|
532
|
+
/** Orden de visualización en UI (menor = primero, default: 999) */
|
|
533
|
+
order?: number;
|
|
446
534
|
}
|
|
447
535
|
/**
|
|
448
536
|
* Entidad computed - KPIs, estadísticas, métricas calculadas
|
|
@@ -469,6 +557,8 @@ interface ComputedEntityDefinition {
|
|
|
469
557
|
casl?: EntityCaslConfig;
|
|
470
558
|
/** Prefijo de ruta para montar */
|
|
471
559
|
routePrefix?: string;
|
|
560
|
+
/** Orden de visualización en UI (menor = primero, default: 999) */
|
|
561
|
+
order?: number;
|
|
472
562
|
}
|
|
473
563
|
/**
|
|
474
564
|
* Entidad view - Vista optimizada para lectura (projections, denormalizaciones)
|
|
@@ -492,6 +582,8 @@ interface ViewEntityDefinition {
|
|
|
492
582
|
casl?: EntityCaslConfig;
|
|
493
583
|
/** Prefijo de ruta para montar */
|
|
494
584
|
routePrefix?: string;
|
|
585
|
+
/** Orden de visualización en UI (menor = primero, default: 999) */
|
|
586
|
+
order?: number;
|
|
495
587
|
}
|
|
496
588
|
/**
|
|
497
589
|
* Entidad config - Configuración por módulo/tenant
|
|
@@ -600,9 +692,56 @@ interface ContextHelpers {
|
|
|
600
692
|
generateId: () => string;
|
|
601
693
|
addTimestamps: (table: Knex.CreateTableBuilder, db: Knex) => void;
|
|
602
694
|
addAuditFieldsIfMissing: (db: Knex, tableName: string) => Promise<void>;
|
|
695
|
+
/** Añade campo is_default a tablas de tipo config */
|
|
696
|
+
addConfigDefaultField: (db: Knex, tableName: string) => Promise<void>;
|
|
603
697
|
addColumnIfMissing: (db: Knex, tableName: string, columnName: string, columnBuilder: (table: Knex.AlterTableBuilder) => void) => Promise<boolean>;
|
|
604
698
|
getLibPath: () => string;
|
|
605
699
|
getProjectPath: () => string;
|
|
700
|
+
/** Timestamp formateado para el driver de BD actual (MySQL: 'YYYY-MM-DD HH:MM:SS', otros: ISO 8601) */
|
|
701
|
+
nowTimestamp: (db: Knex) => string;
|
|
702
|
+
/** Formatea una fecha para el driver de BD actual */
|
|
703
|
+
formatTimestamp: (db: Knex, date?: Date) => string;
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Utilidades criptográficas del contexto
|
|
707
|
+
*/
|
|
708
|
+
interface ContextCrypto {
|
|
709
|
+
/** Hash de password usando bcrypt (cost factor 12) */
|
|
710
|
+
hashPassword: (password: string) => Promise<string>;
|
|
711
|
+
/** Verifica password contra hash bcrypt (timing-safe) */
|
|
712
|
+
verifyPassword: (password: string, hash: string) => Promise<boolean>;
|
|
713
|
+
/** Hash dummy para timing-safe comparison cuando usuario no existe */
|
|
714
|
+
DUMMY_HASH: string;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* API de Socket.IO del contexto
|
|
718
|
+
* @note Solo disponible si Socket.IO está inicializado
|
|
719
|
+
*/
|
|
720
|
+
interface ContextSocket {
|
|
721
|
+
/** Obtiene la instancia de Socket.IO (throws si no inicializado) */
|
|
722
|
+
getIO: () => unknown;
|
|
723
|
+
/** Verifica si Socket.IO está inicializado */
|
|
724
|
+
isInitialized: () => boolean;
|
|
725
|
+
/** Verifica si un usuario específico está conectado */
|
|
726
|
+
isUserConnected: (userId: string) => boolean;
|
|
727
|
+
/** Obtiene el número de sockets conectados para un usuario */
|
|
728
|
+
getUserSocketCount: (userId: string) => number;
|
|
729
|
+
/** Obtiene los IDs de usuarios conectados */
|
|
730
|
+
getConnectedUsers: () => string[];
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* API del Engine para introspección de módulos y plugins
|
|
734
|
+
* Permite acceder al registro de módulos y plugins cargados
|
|
735
|
+
*/
|
|
736
|
+
interface ContextEngine {
|
|
737
|
+
/** Obtiene todos los módulos registrados */
|
|
738
|
+
getModules: () => ModuleManifest[];
|
|
739
|
+
/** Obtiene todos los plugins registrados */
|
|
740
|
+
getPlugins: () => PluginManifest[];
|
|
741
|
+
/** Obtiene los subjects CASL de un módulo específico */
|
|
742
|
+
getModuleSubjects: (mod: ModuleManifest) => string[];
|
|
743
|
+
/** Obtiene todos los subjects CASL registrados en el sistema */
|
|
744
|
+
getRegisteredSubjects: () => string[];
|
|
606
745
|
}
|
|
607
746
|
/**
|
|
608
747
|
* Schema de validación genérico (compatible con Zod sin depender de él)
|
|
@@ -780,31 +919,16 @@ interface ConfigEntityService<T = unknown> extends BaseEntityService<T> {
|
|
|
780
919
|
set(key: string, value: unknown, userId?: string): Promise<T>;
|
|
781
920
|
getAll(): Promise<Record<string, unknown>>;
|
|
782
921
|
}
|
|
783
|
-
/**
|
|
784
|
-
|
|
785
|
-
*/
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
/**
|
|
794
|
-
* Servicio para entidades Computed (campos calculados, solo lectura)
|
|
795
|
-
*/
|
|
796
|
-
interface ComputedEntityService<T = unknown> extends BaseEntityService<T> {
|
|
797
|
-
}
|
|
798
|
-
/**
|
|
799
|
-
* Servicio para entidades External (datos de API externa)
|
|
800
|
-
*/
|
|
801
|
-
interface ExternalEntityService<T = unknown> extends BaseEntityService<T> {
|
|
802
|
-
}
|
|
803
|
-
/**
|
|
804
|
-
* Servicio para entidades Virtual (orquestación de múltiples fuentes)
|
|
805
|
-
*/
|
|
806
|
-
interface VirtualEntityService<T = unknown> extends BaseEntityService<T> {
|
|
807
|
-
}
|
|
922
|
+
/** Servicio para entidades Reference (lectura con join automático) */
|
|
923
|
+
type ReferenceEntityService<T = unknown> = BaseEntityService<T>;
|
|
924
|
+
/** Servicio para entidades View (vista SQL, solo lectura) */
|
|
925
|
+
type ViewEntityService<T = unknown> = BaseEntityService<T>;
|
|
926
|
+
/** Servicio para entidades Computed (campos calculados, solo lectura) */
|
|
927
|
+
type ComputedEntityService<T = unknown> = BaseEntityService<T>;
|
|
928
|
+
/** Servicio para entidades External (datos de API externa) */
|
|
929
|
+
type ExternalEntityService<T = unknown> = BaseEntityService<T>;
|
|
930
|
+
/** Servicio para entidades Virtual (orquestación de múltiples fuentes) */
|
|
931
|
+
type VirtualEntityService<T = unknown> = BaseEntityService<T>;
|
|
808
932
|
/**
|
|
809
933
|
* Servicio para entidades Action (ejecutar acciones)
|
|
810
934
|
*/
|
|
@@ -892,12 +1016,20 @@ interface ModuleContext {
|
|
|
892
1016
|
db: Knex;
|
|
893
1017
|
logger: Logger;
|
|
894
1018
|
helpers: ContextHelpers;
|
|
1019
|
+
/** Utilidades criptográficas (hashPassword, verifyPassword) */
|
|
1020
|
+
crypto: ContextCrypto;
|
|
1021
|
+
/** API de Socket.IO para comunicación en tiempo real */
|
|
1022
|
+
socket: ContextSocket;
|
|
1023
|
+
/** API del Engine para introspección de módulos y plugins */
|
|
1024
|
+
engine: ContextEngine;
|
|
895
1025
|
createRouter: () => Router;
|
|
896
1026
|
middleware: ModuleMiddlewares;
|
|
897
1027
|
/** Configuración resuelta de la aplicación */
|
|
898
1028
|
config: Record<string, unknown>;
|
|
899
1029
|
errors: {
|
|
900
|
-
AppError: new (message: string, statusCode?: number) => Error
|
|
1030
|
+
AppError: new (message: string, statusCode?: number, details?: unknown) => Error & {
|
|
1031
|
+
details?: unknown;
|
|
1032
|
+
};
|
|
901
1033
|
NotFoundError: new (message?: string) => Error;
|
|
902
1034
|
UnauthorizedError: new (message?: string) => Error;
|
|
903
1035
|
ForbiddenError: new (message?: string) => Error;
|
|
@@ -997,4 +1129,4 @@ interface PluginManifest {
|
|
|
997
1129
|
modules: ModuleManifest[];
|
|
998
1130
|
}
|
|
999
1131
|
|
|
1000
|
-
export { type AbilityLike, type ActionEntityDefinition, type ActionEntityService, type AuthRequest, type BaseEntityService, type BaseMailService, type BaseRolesService, type BaseUser, type BaseUsersService, CATEGORIES, CATEGORY_ORDER, type CaslAction, type Category, type CategoryMeta, type CollectionEntityDefinition, type CollectionEntityService, type ComputedEntityDefinition, type ComputedEntityService, type ConfigEntityDefinition, type ConfigEntityService, type ContextHelpers, type CoreServices, type CreateEntityServiceOptions, type DbType, type EntityCaslConfig, type EntityController, type EntityDefinition, type EntityHandler, type EntityIndex, type EntityQuery, type EntityServiceHooks, type EntityType, type EventEmitterLike, type EventEntityDefinition, type EventEntityService, type ExternalEntityDefinition, type ExternalEntityService, type FieldCaslAccess, type FieldDbConfig, type FieldDefinition, type FieldMeta, type FieldOptions, type FieldRelation, type FieldStorageConfig, type FieldValidationConfig, type ForbiddenErrorConstructor, type ForbiddenErrorInstance, type InputType, type KnexAlterTableBuilder, type KnexCreateTableBuilder, type KnexTransaction, type LoggerReporter, type ModuleAbilities, type ModuleContext, type ModuleManifest, type ModuleMiddlewares, type ModuleRequirements, type NonPersistentEntityDefinition, type OwnershipCondition, type PaginatedResult, type PaginationParams, type PersistentEntityDefinition, type PluginAuthRequest, type PluginManifest, type ReferenceEntityDefinition, type ReferenceEntityService, type RolePermission, type SendMailOptions, type SendMailResult, type SingleEntityDefinition, type SingleEntityService, type TempEntityDefinition, type TempEntityService, type ValidateSchemas, type ValidationSchema, type ViewEntityDefinition, type ViewEntityService, type VirtualEntityDefinition, type VirtualEntityService, getEntityName, getEntitySubject, hasTable, isPersistentEntity, isSingletonEntity };
|
|
1132
|
+
export { type AbilityLike, type ActionEntityDefinition, type ActionEntityService, type AuthRequest, type BaseEntityService, type BaseMailService, type BaseRolesService, type BaseUser, type BaseUsersService, CATEGORIES, CATEGORY_ORDER, type CaslAction, type Category, type CategoryMeta, type CollectionEntityDefinition, type CollectionEntityService, type ComputedEntityDefinition, type ComputedEntityService, type ConfigEntityDefinition, type ConfigEntityService, type ContextCrypto, type ContextEngine, type ContextHelpers, type ContextSocket, type CoreServices, type CreateEntityServiceOptions, type DbType, type EntityAction, type EntityCaslConfig, type EntityController, type EntityDefinition, type EntityHandler, type EntityIndex, type EntityQuery, type EntityServiceHooks, type EntityType, type EventEmitterLike, type EventEntityDefinition, type EventEntityService, type ExternalEntityDefinition, type ExternalEntityService, type FieldCaslAccess, type FieldDbConfig, type FieldDefinition, type FieldMeta, type FieldOptions, type FieldRelation, type FieldStorageConfig, type FieldValidationConfig, type ForbiddenErrorConstructor, type ForbiddenErrorInstance, type InputType, type KnexAlterTableBuilder, type KnexCreateTableBuilder, type KnexTransaction, type LoggerReporter, type ModuleAbilities, type ModuleContext, type ModuleManifest, type ModuleMiddlewares, type ModuleRequirements, type NonPersistentEntityDefinition, type OwnershipCondition, type PaginatedResult, type PaginationParams, type PersistentEntityDefinition, type PluginAuthRequest, type PluginManifest, type ReferenceEntityDefinition, type ReferenceEntityService, type RolePermission, type SendMailOptions, type SendMailResult, type SingleEntityDefinition, type SingleEntityService, type TempEntityDefinition, type TempEntityService, type ValidateSchemas, type ValidationSchema, type ViewEntityDefinition, type ViewEntityService, type VirtualEntityDefinition, type VirtualEntityService, getEntityName, getEntitySubject, hasTable, isPersistentEntity, isSingletonEntity };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gzl10/nexus-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "SDK types for creating Nexus plugins and modules",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,22 +23,12 @@
|
|
|
23
23
|
],
|
|
24
24
|
"author": "Gonzalo Díez <gonzalo@gzl10.com>",
|
|
25
25
|
"license": "MIT",
|
|
26
|
-
"homepage": "https://www.gzl10.com",
|
|
27
|
-
"repository": {
|
|
28
|
-
"type": "git",
|
|
29
|
-
"url": "https://gitlab.gzl10.com/oss/nexus-sdk"
|
|
30
|
-
},
|
|
31
|
-
"funding": {
|
|
32
|
-
"type": "github",
|
|
33
|
-
"url": "https://github.com/sponsors/gzl10"
|
|
34
|
-
},
|
|
35
26
|
"devDependencies": {
|
|
36
27
|
"@types/express": "^5.0.2",
|
|
37
28
|
"express": "^5.0.1",
|
|
38
29
|
"knex": "^3.1.0",
|
|
39
30
|
"pino": "^9.6.0",
|
|
40
|
-
"tsup": "^8.4.0"
|
|
41
|
-
"typescript": "^5.8.3"
|
|
31
|
+
"tsup": "^8.4.0"
|
|
42
32
|
},
|
|
43
33
|
"peerDependencies": {
|
|
44
34
|
"express": "^5.0.1",
|
|
@@ -62,6 +52,8 @@
|
|
|
62
52
|
},
|
|
63
53
|
"scripts": {
|
|
64
54
|
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
65
|
-
"typecheck": "tsc --noEmit"
|
|
55
|
+
"typecheck": "tsc --noEmit",
|
|
56
|
+
"lint": "eslint src",
|
|
57
|
+
"clean": "rm -rf dist node_modules"
|
|
66
58
|
}
|
|
67
59
|
}
|
package/README.md
DELETED
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
# @gzl10/nexus-sdk
|
|
2
|
-
|
|
3
|
-
TypeScript SDK for creating plugins and modules compatible with [Nexus Backend](https://gitlab.gzl10.com/oss/nexus-backend).
|
|
4
|
-
|
|
5
|
-
Define module and plugin manifests with full type safety without depending on the full `@gzl10/nexus-backend` package.
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install @gzl10/nexus-sdk
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @gzl10/nexus-sdk
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Usage
|
|
16
|
-
|
|
17
|
-
### Define a module
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import type { ModuleManifest, PluginAuthRequest } from '@gzl10/nexus-sdk'
|
|
21
|
-
|
|
22
|
-
export const tasksModule: ModuleManifest = {
|
|
23
|
-
name: 'tasks',
|
|
24
|
-
label: 'Tasks',
|
|
25
|
-
icon: 'mdi:checkbox-marked-outline',
|
|
26
|
-
description: 'Task management',
|
|
27
|
-
|
|
28
|
-
dependencies: ['users'],
|
|
29
|
-
|
|
30
|
-
migrate: async (ctx) => {
|
|
31
|
-
const { db, helpers } = ctx
|
|
32
|
-
const exists = await db.schema.hasTable('tasks')
|
|
33
|
-
if (!exists) {
|
|
34
|
-
await db.schema.createTable('tasks', (table) => {
|
|
35
|
-
table.string('id').primary()
|
|
36
|
-
table.string('title').notNullable()
|
|
37
|
-
table.text('description')
|
|
38
|
-
table.boolean('completed').defaultTo(false)
|
|
39
|
-
table.string('created_by').references('id').inTable('users')
|
|
40
|
-
helpers.addTimestamps(table, db)
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
routes: (ctx) => {
|
|
46
|
-
const router = ctx.createRouter()
|
|
47
|
-
const { abilities, services } = ctx
|
|
48
|
-
|
|
49
|
-
router.get('/', async (req: PluginAuthRequest, res) => {
|
|
50
|
-
// Check permissions with CASL
|
|
51
|
-
abilities.ForbiddenError.from(req.ability).throwUnlessCan('read', 'tasks')
|
|
52
|
-
|
|
53
|
-
const tasks = await ctx.db('tasks').select('*')
|
|
54
|
-
|
|
55
|
-
// Resolve user relations
|
|
56
|
-
const userIds = [...new Set(tasks.map(t => t.created_by).filter(Boolean))]
|
|
57
|
-
const users = await services.users?.findByIds(userIds) ?? []
|
|
58
|
-
|
|
59
|
-
res.json({ tasks, users })
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
return router
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
entities: [
|
|
66
|
-
{
|
|
67
|
-
name: 'tasks',
|
|
68
|
-
label: 'Tasks',
|
|
69
|
-
labelField: 'title',
|
|
70
|
-
listFields: { title: 'Title', completed: 'Completed' },
|
|
71
|
-
formFields: {
|
|
72
|
-
title: { label: 'Title', type: 'text', required: true },
|
|
73
|
-
description: { label: 'Description', type: 'textarea' },
|
|
74
|
-
completed: { label: 'Completed', type: 'checkbox' }
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Define a plugin (groups modules)
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import type { PluginManifest } from '@gzl10/nexus-sdk'
|
|
85
|
-
import { tasksModule } from './modules/tasks'
|
|
86
|
-
import { projectsModule } from './modules/projects'
|
|
87
|
-
|
|
88
|
-
export const projectPlugin: PluginManifest = {
|
|
89
|
-
name: '@myorg/nexus-projects',
|
|
90
|
-
label: 'Projects',
|
|
91
|
-
icon: 'mdi:folder-outline',
|
|
92
|
-
category: 'content',
|
|
93
|
-
version: '1.0.0',
|
|
94
|
-
description: 'Project management plugin',
|
|
95
|
-
modules: [tasksModule, projectsModule]
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## EntityDefinition (v0.2.0+)
|
|
100
|
-
|
|
101
|
-
Define entities as single source of truth for DB, validation, UI, and CASL:
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
import type { EntityDefinition } from '@gzl10/nexus-sdk'
|
|
105
|
-
|
|
106
|
-
export const postEntity: EntityDefinition = {
|
|
107
|
-
table: 'cms_posts',
|
|
108
|
-
label: 'Posts',
|
|
109
|
-
labelField: 'title',
|
|
110
|
-
timestamps: true,
|
|
111
|
-
audit: true,
|
|
112
|
-
|
|
113
|
-
fields: {
|
|
114
|
-
id: {
|
|
115
|
-
name: 'id',
|
|
116
|
-
label: 'ID',
|
|
117
|
-
input: 'hidden',
|
|
118
|
-
db: { type: 'uuid', nullable: false, defaultFn: 'uuid' }
|
|
119
|
-
},
|
|
120
|
-
title: {
|
|
121
|
-
name: 'title',
|
|
122
|
-
label: 'Title',
|
|
123
|
-
input: 'text',
|
|
124
|
-
db: { type: 'string', size: 200, nullable: false },
|
|
125
|
-
validation: { required: true, min: 3, max: 200 },
|
|
126
|
-
meta: { searchable: true, sortable: true }
|
|
127
|
-
},
|
|
128
|
-
content: {
|
|
129
|
-
name: 'content',
|
|
130
|
-
label: 'Content',
|
|
131
|
-
input: 'markdown',
|
|
132
|
-
db: { type: 'text', nullable: true }
|
|
133
|
-
},
|
|
134
|
-
status: {
|
|
135
|
-
name: 'status',
|
|
136
|
-
label: 'Status',
|
|
137
|
-
input: 'select',
|
|
138
|
-
db: { type: 'string', nullable: false, default: 'draft' },
|
|
139
|
-
validation: { enum: ['draft', 'published', 'archived'] },
|
|
140
|
-
options: {
|
|
141
|
-
static: [
|
|
142
|
-
{ value: 'draft', label: 'Draft' },
|
|
143
|
-
{ value: 'published', label: 'Published' },
|
|
144
|
-
{ value: 'archived', label: 'Archived' }
|
|
145
|
-
]
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
casl: {
|
|
151
|
-
ownership: { field: 'created_by' },
|
|
152
|
-
permissions: {
|
|
153
|
-
ADMIN: { actions: ['manage'] },
|
|
154
|
-
EDITOR: { actions: ['create', 'read', 'update'] },
|
|
155
|
-
VIEWER: { actions: ['read'] }
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### Code Generators
|
|
162
|
-
|
|
163
|
-
Generate TypeScript interfaces from EntityDefinitions:
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import { generateModel, generateModelsFile } from '@gzl10/nexus-sdk'
|
|
167
|
-
|
|
168
|
-
// Generate TypeScript interface for a single entity
|
|
169
|
-
const modelCode = generateModel(postEntity)
|
|
170
|
-
// Creates: export interface Post { ... }
|
|
171
|
-
|
|
172
|
-
// Generate models file for multiple entities
|
|
173
|
-
const modelsFile = generateModelsFile([postEntity, userEntity])
|
|
174
|
-
// Creates consolidated models file with all interfaces
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
> **Note:** Zod schemas and migrations are now generated at runtime by `@gzl10/nexus-backend`.
|
|
178
|
-
|
|
179
|
-
## CLI (v0.5.0+)
|
|
180
|
-
|
|
181
|
-
Generate TypeScript models from EntityDefinitions in your modules:
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
# Install globally or use npx
|
|
185
|
-
npx @gzl10/nexus-sdk generate
|
|
186
|
-
|
|
187
|
-
# Generate for all modules in src/modules
|
|
188
|
-
nexus-sdk generate --path src/modules
|
|
189
|
-
|
|
190
|
-
# Generate for specific module
|
|
191
|
-
nexus-sdk generate --module users
|
|
192
|
-
|
|
193
|
-
# Watch mode for development
|
|
194
|
-
nexus-sdk generate --watch
|
|
195
|
-
|
|
196
|
-
# Dry run (preview without writing)
|
|
197
|
-
nexus-sdk generate --dry-run --verbose
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### CLI Options
|
|
201
|
-
|
|
202
|
-
| Option | Default | Description |
|
|
203
|
-
|--------|---------|-------------|
|
|
204
|
-
| `-p, --path <dir>` | `src/modules` | Base modules directory |
|
|
205
|
-
| `-m, --module <name>` | - | Generate only specific module |
|
|
206
|
-
| `-o, --output <dir>` | `__generated__` | Output directory name |
|
|
207
|
-
| `-w, --watch` | - | Watch for changes and regenerate |
|
|
208
|
-
| `--dry-run` | - | Show what would be generated |
|
|
209
|
-
| `--verbose` | - | Show detailed logs |
|
|
210
|
-
|
|
211
|
-
### Generated Files
|
|
212
|
-
|
|
213
|
-
For each module with `definitions`, the CLI generates:
|
|
214
|
-
|
|
215
|
-
```text
|
|
216
|
-
src/modules/posts/
|
|
217
|
-
├── index.ts # Module manifest with definitions
|
|
218
|
-
└── __generated__/
|
|
219
|
-
└── posts.models.ts # TypeScript interfaces
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Module Structure
|
|
223
|
-
|
|
224
|
-
The CLI discovers modules by looking for `index.ts` files that export a `ModuleManifest` with `definitions`:
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
// src/modules/posts/index.ts
|
|
228
|
-
import type { ModuleManifest, EntityDefinition } from '@gzl10/nexus-sdk'
|
|
229
|
-
|
|
230
|
-
const postEntity: EntityDefinition = {
|
|
231
|
-
type: 'collection',
|
|
232
|
-
table: 'posts',
|
|
233
|
-
// ...
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export const postsModule: ModuleManifest = {
|
|
237
|
-
name: 'posts',
|
|
238
|
-
label: 'Posts',
|
|
239
|
-
definitions: [postEntity]
|
|
240
|
-
}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## Main Types
|
|
244
|
-
|
|
245
|
-
### Manifests & Context
|
|
246
|
-
|
|
247
|
-
| Type | Description |
|
|
248
|
-
|------|-------------|
|
|
249
|
-
| `ModuleManifest` | Defines a module: routes, migrations, seeds, entities |
|
|
250
|
-
| `PluginManifest` | Groups modules under a plugin with shared metadata |
|
|
251
|
-
| `ModuleContext` | Context injected by Nexus: `db`, `logger`, `helpers`, `services`, `abilities` |
|
|
252
|
-
|
|
253
|
-
### Entity Definition System
|
|
254
|
-
|
|
255
|
-
| Type | Description |
|
|
256
|
-
|------|-------------|
|
|
257
|
-
| `EntityDefinition` | Complete entity definition (DB, UI, validation, CASL) |
|
|
258
|
-
| `FieldDefinition` | Field configuration with DB, UI, and validation settings |
|
|
259
|
-
| `FieldDbConfig` | Database column configuration |
|
|
260
|
-
| `FieldRelation` | Foreign key configuration |
|
|
261
|
-
| `EntityCaslConfig` | CASL authorization configuration |
|
|
262
|
-
|
|
263
|
-
### Entity Types (Discriminated Union)
|
|
264
|
-
|
|
265
|
-
| Type | Description |
|
|
266
|
-
|------|-------------|
|
|
267
|
-
| `CollectionEntity` | Full CRUD (users, posts) |
|
|
268
|
-
| `ReferenceEntity` | Catalogs with admin CRUD (countries) |
|
|
269
|
-
| `SingleEntity` | Singleton, update/read only (site_config) |
|
|
270
|
-
| `ConfigEntity` | Per-module config, singleton |
|
|
271
|
-
| `ExternalEntity` | Read-only from external systems |
|
|
272
|
-
| `VirtualEntity` | Orchestration of multiple sources |
|
|
273
|
-
| `ComputedEntity` | KPIs, calculated stats |
|
|
274
|
-
| `ViewEntity` | Optimized read projections |
|
|
275
|
-
| `EventEntity` | Audit logs, append-only |
|
|
276
|
-
| `TempEntity` | TTL-based (cache, sessions) |
|
|
277
|
-
| `ActionEntity` | Commands without persistence |
|
|
278
|
-
|
|
279
|
-
### Request & Auth
|
|
280
|
-
|
|
281
|
-
| Type | Description |
|
|
282
|
-
|------|-------------|
|
|
283
|
-
| `AuthRequest<TUser, TAbility>` | Generic authenticated request |
|
|
284
|
-
| `PluginAuthRequest` | Pre-typed `AuthRequest<BaseUser, AbilityLike>` for plugins |
|
|
285
|
-
| `BaseUser` | User without password for relations |
|
|
286
|
-
| `AbilityLike` | Generic CASL ability interface (`can`, `cannot`) |
|
|
287
|
-
|
|
288
|
-
### Services & Utilities
|
|
289
|
-
|
|
290
|
-
| Type | Description |
|
|
291
|
-
|------|-------------|
|
|
292
|
-
| `EntityType` | Union of all entity type strings |
|
|
293
|
-
| `PaginationParams` | Pagination input (`page`, `limit`) |
|
|
294
|
-
| `PaginatedResult<T>` | Paginated response with metadata |
|
|
295
|
-
| `ValidationSchema` | Generic Zod-compatible schema interface |
|
|
296
|
-
|
|
297
|
-
### ModuleContext
|
|
298
|
-
|
|
299
|
-
The context provides access to:
|
|
300
|
-
|
|
301
|
-
- `db` - Knex instance for queries
|
|
302
|
-
- `logger` - Pino logger
|
|
303
|
-
- `helpers` - Migration utilities (`addTimestamps`, `addColumnIfMissing`)
|
|
304
|
-
- `createRouter()` - Express Router factory
|
|
305
|
-
- `middleware.validate()` - Request validation with Zod schemas
|
|
306
|
-
- `errors` - Error classes (`AppError`, `NotFoundError`, `UnauthorizedError`, etc.)
|
|
307
|
-
- `abilities` - CASL helpers (`subject`, `ForbiddenError`)
|
|
308
|
-
- `services` - Registered services (extensible)
|
|
309
|
-
- `events` - EventEmitter for inter-module communication
|
|
310
|
-
- `mail` - Email sending service
|
|
311
|
-
|
|
312
|
-
### Re-exported Types
|
|
313
|
-
|
|
314
|
-
For convenience, the SDK re-exports commonly used types:
|
|
315
|
-
|
|
316
|
-
- **Express:** `Request`, `Response`, `NextFunction`, `RequestHandler`, `Router`, `CookieOptions`
|
|
317
|
-
- **Knex:** `Knex`, `KnexCreateTableBuilder`, `KnexAlterTableBuilder`, `KnexTransaction`
|
|
318
|
-
|
|
319
|
-
## License
|
|
320
|
-
|
|
321
|
-
MIT © [Gonzalo Díez](https://www.gzl10.com)
|