@gzl10/nexus-sdk 0.1.4
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/README.md +116 -0
- package/dist/index.d.ts +187 -0
- package/dist/index.js +0 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
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 } from '@gzl10/nexus-sdk'
|
|
21
|
+
|
|
22
|
+
export const tasksModule: ModuleManifest = {
|
|
23
|
+
name: 'tasks',
|
|
24
|
+
code: 'TSK',
|
|
25
|
+
label: 'Tasks',
|
|
26
|
+
icon: 'mdi:checkbox-marked-outline',
|
|
27
|
+
description: 'Task management',
|
|
28
|
+
|
|
29
|
+
dependencies: ['users'],
|
|
30
|
+
|
|
31
|
+
migrate: async (ctx) => {
|
|
32
|
+
const { db, helpers } = ctx
|
|
33
|
+
const exists = await db.schema.hasTable('tasks')
|
|
34
|
+
if (!exists) {
|
|
35
|
+
await db.schema.createTable('tasks', (table) => {
|
|
36
|
+
table.string('id').primary()
|
|
37
|
+
table.string('title').notNullable()
|
|
38
|
+
table.text('description')
|
|
39
|
+
table.boolean('completed').defaultTo(false)
|
|
40
|
+
helpers.addTimestamps(table, db)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
routes: (ctx) => {
|
|
46
|
+
const router = ctx.createRouter()
|
|
47
|
+
|
|
48
|
+
router.get('/', async (req, res) => {
|
|
49
|
+
const tasks = await ctx.db('tasks').select('*')
|
|
50
|
+
res.json(tasks)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return router
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
entities: [
|
|
57
|
+
{
|
|
58
|
+
name: 'tasks',
|
|
59
|
+
label: 'Tasks',
|
|
60
|
+
labelField: 'title',
|
|
61
|
+
listFields: { title: 'Title', completed: 'Completed' },
|
|
62
|
+
formFields: {
|
|
63
|
+
title: { label: 'Title', type: 'text', required: true },
|
|
64
|
+
description: { label: 'Description', type: 'textarea' },
|
|
65
|
+
completed: { label: 'Completed', type: 'checkbox' }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Define a plugin (groups modules)
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import type { PluginManifest } from '@gzl10/nexus-sdk'
|
|
76
|
+
import { tasksModule } from './modules/tasks'
|
|
77
|
+
import { projectsModule } from './modules/projects'
|
|
78
|
+
|
|
79
|
+
export const projectPlugin: PluginManifest = {
|
|
80
|
+
name: '@myorg/nexus-projects',
|
|
81
|
+
code: 'PRJ',
|
|
82
|
+
label: 'Projects',
|
|
83
|
+
icon: 'mdi:folder-outline',
|
|
84
|
+
category: 'content',
|
|
85
|
+
version: '1.0.0',
|
|
86
|
+
description: 'Project management plugin',
|
|
87
|
+
modules: [tasksModule, projectsModule]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Main Types
|
|
92
|
+
|
|
93
|
+
| Type | Description |
|
|
94
|
+
|------|-------------|
|
|
95
|
+
| `ModuleManifest` | Defines a module: routes, migrations, seeds, CRUD entities |
|
|
96
|
+
| `PluginManifest` | Groups modules under a plugin with shared metadata |
|
|
97
|
+
| `ModuleContext` | Context injected by Nexus: `db`, `logger`, `helpers`, `events`, `mail` |
|
|
98
|
+
| `ModuleEntity` | Declarative entity configuration for CRUD UI |
|
|
99
|
+
| `FormField` | Form field configuration with validation |
|
|
100
|
+
|
|
101
|
+
### ModuleContext
|
|
102
|
+
|
|
103
|
+
The context provides access to:
|
|
104
|
+
|
|
105
|
+
- `db` - Knex instance for queries
|
|
106
|
+
- `logger` - Pino logger
|
|
107
|
+
- `helpers` - Migration utilities (`addTimestamps`, `addColumnIfMissing`)
|
|
108
|
+
- `createRouter()` - Express Router factory
|
|
109
|
+
- `middleware` - Registered middlewares (includes `validate`)
|
|
110
|
+
- `errors` - Error classes (`AppError`, `NotFoundError`, `UnauthorizedError`, etc.)
|
|
111
|
+
- `events` - EventEmitter for inter-module communication
|
|
112
|
+
- `mail` - Email sending service
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT © [Gonzalo Díez](https://www.gzl10.com)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Knex } from 'knex';
|
|
2
|
+
import { RequestHandler, Router } from 'express';
|
|
3
|
+
export { CookieOptions, NextFunction, Request, RequestHandler, Response, Router } from 'express';
|
|
4
|
+
import { Logger } from 'pino';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @gzl10/nexus-sdk
|
|
8
|
+
*
|
|
9
|
+
* SDK types for creating Nexus plugins and modules.
|
|
10
|
+
* Use this package to define plugin/module manifests without
|
|
11
|
+
* depending on the full @gzl10/nexus-backend package.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Tipo de campo para formularios dinámicos
|
|
16
|
+
*/
|
|
17
|
+
type FormFieldType = 'text' | 'email' | 'password' | 'number' | 'textarea' | 'markdown' | 'select' | 'checkbox' | 'date' | 'datetime';
|
|
18
|
+
/**
|
|
19
|
+
* JSON Schema para validación de campos (subset serializable)
|
|
20
|
+
*/
|
|
21
|
+
interface FieldValidation {
|
|
22
|
+
type?: 'string' | 'number' | 'integer' | 'boolean';
|
|
23
|
+
minLength?: number;
|
|
24
|
+
maxLength?: number;
|
|
25
|
+
minimum?: number;
|
|
26
|
+
maximum?: number;
|
|
27
|
+
pattern?: string;
|
|
28
|
+
format?: 'email' | 'uri' | 'date' | 'date-time' | 'uuid';
|
|
29
|
+
errorMessage?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Configuración de un campo de formulario
|
|
33
|
+
*/
|
|
34
|
+
interface FormField {
|
|
35
|
+
label: string;
|
|
36
|
+
type: FormFieldType;
|
|
37
|
+
required?: boolean;
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
createOnly?: boolean;
|
|
40
|
+
disabled?: boolean;
|
|
41
|
+
hidden?: boolean;
|
|
42
|
+
optionsEndpoint?: string;
|
|
43
|
+
optionValue?: string;
|
|
44
|
+
optionLabel?: string;
|
|
45
|
+
validation?: FieldValidation;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Tipo de visualización de lista
|
|
49
|
+
*/
|
|
50
|
+
type ListType = 'table' | 'list' | 'grid' | 'masonry';
|
|
51
|
+
/**
|
|
52
|
+
* Configuración de una entidad/tabla del módulo para UI CRUD
|
|
53
|
+
*/
|
|
54
|
+
interface ModuleEntity {
|
|
55
|
+
name: string;
|
|
56
|
+
label: string;
|
|
57
|
+
listFields: Record<string, string>;
|
|
58
|
+
formFields?: Record<string, FormField>;
|
|
59
|
+
labelField: string;
|
|
60
|
+
routePrefix?: string;
|
|
61
|
+
editMode?: 'modal' | 'page';
|
|
62
|
+
listType?: ListType;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Requisitos para activar un módulo
|
|
66
|
+
*/
|
|
67
|
+
interface ModuleRequirements {
|
|
68
|
+
env?: string[];
|
|
69
|
+
modules?: string[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Helpers para migraciones de base de datos
|
|
73
|
+
*/
|
|
74
|
+
interface MigrationHelpers {
|
|
75
|
+
addTimestamps: (table: Knex.CreateTableBuilder, db: Knex) => void;
|
|
76
|
+
addAuditFieldsIfMissing: (db: Knex, tableName: string) => Promise<void>;
|
|
77
|
+
addColumnIfMissing: (db: Knex, tableName: string, columnName: string, columnBuilder: (table: Knex.AlterTableBuilder) => void) => Promise<boolean>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Middlewares disponibles en el contexto
|
|
81
|
+
*/
|
|
82
|
+
interface ModuleMiddlewares {
|
|
83
|
+
validate: (schemas: {
|
|
84
|
+
body?: unknown;
|
|
85
|
+
query?: unknown;
|
|
86
|
+
params?: unknown;
|
|
87
|
+
}) => RequestHandler;
|
|
88
|
+
[key: string]: RequestHandler | ((...args: unknown[]) => RequestHandler) | undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Contexto inyectado a los módulos
|
|
92
|
+
*/
|
|
93
|
+
interface ModuleContext {
|
|
94
|
+
db: Knex;
|
|
95
|
+
logger: Logger;
|
|
96
|
+
generateId: () => string;
|
|
97
|
+
dbType: 'sqlite' | 'postgresql' | 'mysql';
|
|
98
|
+
helpers: MigrationHelpers;
|
|
99
|
+
createRouter: () => Router;
|
|
100
|
+
middleware: ModuleMiddlewares;
|
|
101
|
+
registerMiddleware: (name: string, handler: RequestHandler) => void;
|
|
102
|
+
config: Record<string, unknown>;
|
|
103
|
+
errors: {
|
|
104
|
+
AppError: new (message: string, statusCode?: number) => Error;
|
|
105
|
+
NotFoundError: new (message: string) => Error;
|
|
106
|
+
UnauthorizedError: new (message: string) => Error;
|
|
107
|
+
ForbiddenError: new (message: string) => Error;
|
|
108
|
+
ConflictError: new (message: string) => Error;
|
|
109
|
+
};
|
|
110
|
+
abilities: Record<string, unknown>;
|
|
111
|
+
events: {
|
|
112
|
+
emit: (event: string, ...args: unknown[]) => boolean;
|
|
113
|
+
on: (event: string, listener: (...args: unknown[]) => void) => unknown;
|
|
114
|
+
};
|
|
115
|
+
mail: {
|
|
116
|
+
send: (options: {
|
|
117
|
+
to: string | string[];
|
|
118
|
+
subject: string;
|
|
119
|
+
html?: string;
|
|
120
|
+
text?: string;
|
|
121
|
+
template?: string;
|
|
122
|
+
data?: Record<string, unknown>;
|
|
123
|
+
}) => Promise<void>;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Manifest de un módulo Nexus
|
|
128
|
+
*/
|
|
129
|
+
interface ModuleManifest {
|
|
130
|
+
/** Identificador único del módulo (ej: 'users', 'posts') */
|
|
131
|
+
name: string;
|
|
132
|
+
/** Código único del módulo (ej: 'USR', 'PST'). Opcional si pertenece a un plugin */
|
|
133
|
+
code?: string;
|
|
134
|
+
/** Nombre para mostrar en UI. Opcional si pertenece a un plugin */
|
|
135
|
+
label?: string;
|
|
136
|
+
/** Icono del módulo (Iconify MDI: 'mdi:account-group') */
|
|
137
|
+
icon?: string;
|
|
138
|
+
/** Descripción del módulo */
|
|
139
|
+
description?: string;
|
|
140
|
+
/** Tipo de módulo */
|
|
141
|
+
type?: 'core' | 'plugin' | 'auth-plugin' | 'custom';
|
|
142
|
+
/** Dependencias de otros módulos */
|
|
143
|
+
dependencies?: string[];
|
|
144
|
+
/** Requisitos para activar el módulo */
|
|
145
|
+
required?: ModuleRequirements;
|
|
146
|
+
/** Función de migración de base de datos */
|
|
147
|
+
migrate?: (ctx: ModuleContext) => Promise<void>;
|
|
148
|
+
/** Función de seed de datos iniciales */
|
|
149
|
+
seed?: (ctx: ModuleContext) => Promise<void>;
|
|
150
|
+
/** Inicialización del módulo */
|
|
151
|
+
init?: (ctx: ModuleContext) => void;
|
|
152
|
+
/** Factory de rutas del módulo */
|
|
153
|
+
routes?: (ctx: ModuleContext) => Router;
|
|
154
|
+
/** Prefijo de rutas (default: /{name}) */
|
|
155
|
+
routePrefix?: string;
|
|
156
|
+
/** Subjects CASL que expone el módulo */
|
|
157
|
+
subjects?: string[];
|
|
158
|
+
/** Entidades/tablas del módulo con config CRUD para UI */
|
|
159
|
+
entities?: ModuleEntity[];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Categorías disponibles para plugins
|
|
163
|
+
*/
|
|
164
|
+
type PluginCategory = 'content' | 'data' | 'storage' | 'messaging' | 'jobs' | 'ai' | 'analytics' | 'integrations' | 'commerce';
|
|
165
|
+
/**
|
|
166
|
+
* Manifest de un plugin Nexus
|
|
167
|
+
*/
|
|
168
|
+
interface PluginManifest {
|
|
169
|
+
/** Nombre del plugin (normalmente el nombre del paquete npm) */
|
|
170
|
+
name: string;
|
|
171
|
+
/** Código del plugin (3-4 chars UPPERCASE). Se hereda a todos los módulos */
|
|
172
|
+
code: string;
|
|
173
|
+
/** Etiqueta para mostrar en UI. Se hereda a los módulos si no la definen */
|
|
174
|
+
label: string;
|
|
175
|
+
/** Icono del plugin (Iconify MDI). Se hereda a los módulos si no lo definen */
|
|
176
|
+
icon?: string;
|
|
177
|
+
/** Categoría del plugin para agrupar en sidebar */
|
|
178
|
+
category?: PluginCategory;
|
|
179
|
+
/** Versión del plugin (semver) */
|
|
180
|
+
version: string;
|
|
181
|
+
/** Descripción del plugin */
|
|
182
|
+
description: string;
|
|
183
|
+
/** Módulos incluidos en el plugin */
|
|
184
|
+
modules: ModuleManifest[];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export type { FieldValidation, FormField, FormFieldType, ListType, MigrationHelpers, ModuleContext, ModuleEntity, ModuleManifest, ModuleMiddlewares, ModuleRequirements, PluginCategory, PluginManifest };
|
package/dist/index.js
ADDED
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gzl10/nexus-sdk",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "SDK types for creating Nexus plugins and modules",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"nexus",
|
|
19
|
+
"backend",
|
|
20
|
+
"sdk",
|
|
21
|
+
"plugin",
|
|
22
|
+
"module"
|
|
23
|
+
],
|
|
24
|
+
"author": "Gonzalo Díez <gonzalo@gzl10.com>",
|
|
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
|
+
"devDependencies": {
|
|
36
|
+
"@types/express": "^5.0.2",
|
|
37
|
+
"express": "^5.0.1",
|
|
38
|
+
"knex": "^3.1.0",
|
|
39
|
+
"pino": "^9.6.0",
|
|
40
|
+
"tsup": "^8.4.0",
|
|
41
|
+
"typescript": "^5.8.3"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"knex": "^3.1.0",
|
|
45
|
+
"express": "^5.0.1",
|
|
46
|
+
"pino": "^9.6.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"knex": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"express": {
|
|
53
|
+
"optional": true
|
|
54
|
+
},
|
|
55
|
+
"pino": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public",
|
|
61
|
+
"registry": "https://registry.npmjs.org"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
65
|
+
"typecheck": "tsc --noEmit"
|
|
66
|
+
}
|
|
67
|
+
}
|