@gzl10/nexus-backend 0.17.0 → 0.18.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 CHANGED
@@ -1,9 +1,10 @@
1
- import http from 'node:http';
1
+ import * as http from 'node:http';
2
+ import http__default from 'node:http';
2
3
  import { Express, Request, Response, Router, NextFunction, RequestHandler } from 'express';
3
4
  export { Express } from 'express';
4
5
  import { AbilityBuilder, MongoAbility, RawRuleOf } from '@casl/ability';
5
6
  import * as _gzl10_nexus_sdk from '@gzl10/nexus-sdk';
6
- import { PluginManifest, ModuleManifest, EntityQuery, PaginatedResult, EntityDefinition, ModuleContext, CreateEntityServiceOptions, BaseEntityService as BaseEntityService$1, EntityServiceHooks, CollectionEntityDefinition, SingleEntityDefinition, ViewEntityDefinition, ExternalEntityDefinition, ComputedEntityDefinition, TreeEntityDefinition, DagEntityDefinition, EntityChangePayload, BridgeRule, ValidateSchemas, SSESender, SSEHelper } from '@gzl10/nexus-sdk';
7
+ import { PluginManifest, ModuleManifest, LocaleConfig, SeedContext, EntityQuery, PaginatedResult, EntityDefinition, ModuleContext, CreateEntityServiceOptions, BaseEntityService as BaseEntityService$1, EntityServiceHooks, CollectionEntityDefinition, SingleEntityDefinition, ViewEntityDefinition, ExternalEntityDefinition, ComputedEntityDefinition, TreeEntityDefinition, DagEntityDefinition, EntityChangePayload, BridgeRule, ValidateSchemas, SSESender, SSEHelper } from '@gzl10/nexus-sdk';
7
8
  export { AuthRequest, AuthorizationParams, Category, ContextHelpers, CookieOptions, DomainFilterOptions, DomainFilterResult, EntityDefinition, EntityQuery, IdTokenClaims, ModuleAbilities, ModuleContext, ModuleManifest, ModuleMiddlewares, ModuleRequirements, NextFunction, OidcClient, OidcDiscoveryDocument, OidcState, OidcTokens, OidcUserInfo, PaginatedResult, PaginationParams, PluginManifest, Request, RequestHandler, Response, Router, SessionResult, StateManager, TokenExchangeParams, TokenValidationConfig, ValidateSchemas, assertAllowedDomain, checkAllowedDomain, createOidcClient, createStateManager, entityRoom, getOidcClient } from '@gzl10/nexus-sdk';
8
9
  import * as express_serve_static_core from 'express-serve-static-core';
9
10
  import * as knex from 'knex';
@@ -56,7 +57,9 @@ interface ServeSPAOptions {
56
57
  * serveSPA('/admin', '../admin/dist', { maxAge: '7d', immutable: true })
57
58
  * ```
58
59
  */
59
- type ServeSPAFunction = (endpoint: string, distPath: string, options?: ServeSPAOptions) => void;
60
+ type ServeSPAFunction = (endpoint: string, distPath: string, options?: ServeSPAOptions & {
61
+ viteSrc?: string;
62
+ }) => void | Promise<void>;
60
63
  /**
61
64
  * Configuration for a frontend SPA.
62
65
  *
@@ -89,6 +92,15 @@ interface SpaEntry extends ServeSPAOptions {
89
92
  path?: string;
90
93
  /** Origin URL for CORS allowlist. Required for external SPAs; optional for served SPAs with a custom domain. */
91
94
  origin?: string;
95
+ /**
96
+ * Path to frontend source directory (dev only).
97
+ * When set in development, mounts Vite dev server as middleware with HMR instead of serving static files.
98
+ * Ignored in production — uses `path` for static files.
99
+ * Requires `endpoint` to be set. Requires `vite` as a peer dependency.
100
+ *
101
+ * @example { endpoint: '/', viteSrc: '../ui', path: '../ui/dist' }
102
+ */
103
+ viteSrc?: string;
92
104
  }
93
105
  /**
94
106
  * Discovered plugins and modules.
@@ -110,6 +122,8 @@ interface NexusConfig {
110
122
  * Auto-discovered from src/modules/ + passed programmatically to start().
111
123
  */
112
124
  modules?: ModuleManifest[];
125
+ /** Supported locales. Default: DEFAULT_LOCALES (en + es) */
126
+ locales?: LocaleConfig[];
113
127
  }
114
128
  /**
115
129
  * Runtime options for `start()`.
@@ -147,10 +161,52 @@ interface StartOptions extends NexusConfig {
147
161
  [eventName: string]: ((data: any) => void | Promise<void>) | undefined;
148
162
  };
149
163
  /**
150
- * Function to define additional CASL rules.
151
- * Runs after loading permissions from the DB.
164
+ * Advanced CASL rules for cases not covered by `seed.roles.add({ permissions })`.
165
+ * Runs as step 3 in the ability factory (after entity definition permissions).
166
+ *
167
+ * **Prefer `onSeed` → `seed.roles.add({ permissions })` for simple role-based permissions.**
168
+ * Use `casl` only when you need:
169
+ * - Conditions: `can('update', 'Post', { authorId: user.id })`
170
+ * - Field-level: `can('read', 'User', ['name', 'email'])`
171
+ * - Denials: `cannot('delete', 'User')`
172
+ * - Dynamic logic based on user properties
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * casl: (user, { can, cannot }) => {
177
+ * if ((user as any).roleNames?.includes('EDITOR')) {
178
+ * can('update', 'Post', { authorId: (user as any).id })
179
+ * cannot('delete', 'Post')
180
+ * }
181
+ * }
182
+ * ```
152
183
  */
153
184
  casl?: CaslRulesFunction;
185
+ /**
186
+ * Callback executed after all module seeds have run.
187
+ * Receives a `SeedContext` with typed helpers — no direct DB access needed.
188
+ *
189
+ * - `seed.masters.register()` — lazy, flushed after callback completes
190
+ * - `seed.roles.add()` — eager, supports `permissions` for CASL assignment
191
+ * - `seed.users.add()` — eager, supports role assignment by name
192
+ * - `seed.plugin(name).entity(name).upsert()` — resolves table prefix automatically
193
+ * - `seed.raw()` — escape hatch for custom tables
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * onSeed: async (seed) => {
198
+ * seed.masters.register('sources', [
199
+ * { code: 'web', label: { en: 'Website', es: 'Sitio web' } }
200
+ * ])
201
+ * await seed.roles.add({
202
+ * name: 'SALES',
203
+ * permissions: { 'contacts': ['read', 'create', 'update'] }
204
+ * })
205
+ * await seed.users.add({ email: 'admin@acme.com', password: 'temp', roles: ['ADMIN'] })
206
+ * }
207
+ * ```
208
+ */
209
+ onSeed?: (seed: SeedContext) => void | Promise<void>;
154
210
  /**
155
211
  * Callback executed when the server is fully ready.
156
212
  * Runs after listen() and Socket.IO initialization.
@@ -198,9 +254,57 @@ interface ResolvedConfig {
198
254
  adminPassword?: string;
199
255
  }
200
256
 
201
- declare function start(config?: StartOptions): Promise<http.Server>;
257
+ /**
258
+ * Starts the Nexus server.
259
+ *
260
+ * Lifecycle order:
261
+ * 1. Logger, DB, migrations
262
+ * 2. Module/plugin registration and seed
263
+ * 3. `onSeed` hook (SeedContext with typed helpers)
264
+ * 4. `beforeRoutes` hook → module routes → `afterRoutes` hook
265
+ * 5. HTTP listen + Socket.IO
266
+ * 6. `onReady` hook
267
+ *
268
+ * @param config - Optional startup configuration (plugins, modules, lifecycle hooks, SPAs)
269
+ * @returns The underlying `http.Server` instance
270
+ * @throws If the server is already running (call `stop()` first)
271
+ *
272
+ * @example
273
+ * ```typescript
274
+ * import { start } from '@gzl10/nexus-backend'
275
+ *
276
+ * const server = await start({
277
+ * onSeed: async (seed) => {
278
+ * await seed.roles.add({ name: 'SALES', permissions: { 'contacts': ['read', 'create'] } })
279
+ * },
280
+ * onReady: (_app, port) => console.log(`Ready on ${port}`)
281
+ * })
282
+ * ```
283
+ */
284
+ declare function start(config?: StartOptions): Promise<http__default.Server>;
285
+ /**
286
+ * Stops the Nexus server gracefully.
287
+ *
288
+ * Closes HTTP server, Socket.IO, database connections, and cleans up all state.
289
+ * Calls `beforeClose` hook if registered. Safe to call multiple times.
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * await stop() // server stopped, port freed
294
+ * ```
295
+ */
202
296
  declare function stop(): Promise<void>;
203
- declare function restart(config?: StartOptions): Promise<http.Server>;
297
+ /**
298
+ * Restarts the Nexus server. Calls `stop()` then `start()`.
299
+ *
300
+ * If no config is provided, reuses the config from the previous `start()` call.
301
+ * Plugins, hooks, and SPAs are preserved across restarts.
302
+ *
303
+ * @param config - Optional new config. If omitted, reuses previous config.
304
+ * @returns The new `http.Server` instance
305
+ */
306
+ declare function restart(config?: StartOptions): Promise<http__default.Server>;
307
+ /** Returns `true` if the server is currently running. */
204
308
  declare function isRunning(): boolean;
205
309
 
206
310
  interface CreateAppOptions {
@@ -208,6 +312,8 @@ interface CreateAppOptions {
208
312
  afterRoutes?: (app: Express, serveSPA: ServeSPAFunction) => void | Promise<void>;
209
313
  /** Declarative SPA entries (served + CORS). Passed from StartOptions.spas. */
210
314
  spas?: SpaEntry[];
315
+ /** HTTP server for Vite HMR WebSocket (shared with Socket.IO) */
316
+ httpServer?: http.Server;
211
317
  }
212
318
  declare function createApp(options?: CreateAppOptions): Promise<express_serve_static_core.Express>;
213
319