@dudousxd/nestjs-durable-dashboard 0.44.0 → 0.45.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.
@@ -239,7 +239,14 @@ declare class RunQueryDraft {
239
239
  facetQuery(): RunFacetQuery;
240
240
  }
241
241
 
242
- /** JSON API consumed by the control-plane SPA. Mounted at `apiBasePath` (set by RouterModule). */
242
+ /**
243
+ * JSON API consumed by the control-plane SPA. Mounted at `apiBasePath` (set by RouterModule).
244
+ *
245
+ * The filter interceptor (what resolves `@ApplyFilter` into a query) is bound HERE rather than as
246
+ * the app-wide `APP_INTERCEPTOR` that `FilterModule.forRoot()` registers: a library must not add a
247
+ * global interceptor to its host, and on an app that already has one this would be the second copy,
248
+ * running every filter in the app twice.
249
+ */
243
250
  declare class DurableApiController {
244
251
  private readonly dashboard;
245
252
  private readonly runner;
@@ -448,24 +455,6 @@ interface DurableDashboardOptions {
448
455
  * (e.g. an `EntityManager` to look up an admin user).
449
456
  */
450
457
  dashboardAuth?: DashboardAuthOptions;
451
- /**
452
- * Who registers `@dudousxd/nestjs-filter`'s core — the console's run filters are written with it.
453
- *
454
- * - `'bootstrap'` (default): this module calls `FilterModule.forRoot()` itself, so the console
455
- * works in an app that has never heard of the filter library.
456
- * - `'host'`: your app already calls `FilterModule.forRoot(...)`; this module registers only its
457
- * own filter and adapter.
458
- *
459
- * It has to be YOUR call rather than something detected, because `forRoot` is a GLOBAL
460
- * registration: called twice, the second one's module options (validation policy, input format,
461
- * page-size ceiling) shadow the first's, and the app-wide interceptor is registered twice. There
462
- * is no moment at module-definition time when this module could see whether you have called it.
463
- *
464
- * Only the core is shared. The console's adapter never is: `RunFilter` names its own via
465
- * `@Filterable({ adapter })`, so your global adapter (your ORM's) keeps answering for your filters
466
- * and the run gateway answers for the console's, in the same process.
467
- */
468
- filterModule?: 'bootstrap' | 'host';
469
458
  }
470
459
  /**
471
460
  * Async variant of {@link DurableDashboardOptions}. The mount paths and `guards` stay static (the
@@ -480,8 +469,6 @@ interface DurableDashboardAsyncOptions {
480
469
  apiBasePath?: string;
481
470
  guards?: Type<CanActivate>[];
482
471
  imports?: DynamicModule['imports'];
483
- /** See {@link DurableDashboardOptions.filterModule}. */
484
- filterModule?: 'bootstrap' | 'host';
485
472
  /** Providers injected into `useDashboardAuth`, in order. Shared with a `guards` class's own deps. */
486
473
  inject?: Array<InjectionToken | OptionalFactoryDependency>;
487
474
  /** Build the `dashboardAuth` config from injected deps (or `undefined` to leave the console open). */
@@ -505,8 +492,6 @@ declare class DurableApiModule {
505
492
  * (true whenever `dashboardAuth` was set, or unconditionally for `forRootAsync`, where it's
506
493
  * resolved at runtime and is a no-op if it ends up unconfigured). */
507
494
  authMayBeConfigured: boolean;
508
- /** See {@link DurableDashboardOptions.filterModule}. */
509
- filterModule?: 'bootstrap' | 'host';
510
495
  }): DynamicModule;
511
496
  }
512
497
  /**
@@ -239,7 +239,14 @@ declare class RunQueryDraft {
239
239
  facetQuery(): RunFacetQuery;
240
240
  }
241
241
 
242
- /** JSON API consumed by the control-plane SPA. Mounted at `apiBasePath` (set by RouterModule). */
242
+ /**
243
+ * JSON API consumed by the control-plane SPA. Mounted at `apiBasePath` (set by RouterModule).
244
+ *
245
+ * The filter interceptor (what resolves `@ApplyFilter` into a query) is bound HERE rather than as
246
+ * the app-wide `APP_INTERCEPTOR` that `FilterModule.forRoot()` registers: a library must not add a
247
+ * global interceptor to its host, and on an app that already has one this would be the second copy,
248
+ * running every filter in the app twice.
249
+ */
243
250
  declare class DurableApiController {
244
251
  private readonly dashboard;
245
252
  private readonly runner;
@@ -448,24 +455,6 @@ interface DurableDashboardOptions {
448
455
  * (e.g. an `EntityManager` to look up an admin user).
449
456
  */
450
457
  dashboardAuth?: DashboardAuthOptions;
451
- /**
452
- * Who registers `@dudousxd/nestjs-filter`'s core — the console's run filters are written with it.
453
- *
454
- * - `'bootstrap'` (default): this module calls `FilterModule.forRoot()` itself, so the console
455
- * works in an app that has never heard of the filter library.
456
- * - `'host'`: your app already calls `FilterModule.forRoot(...)`; this module registers only its
457
- * own filter and adapter.
458
- *
459
- * It has to be YOUR call rather than something detected, because `forRoot` is a GLOBAL
460
- * registration: called twice, the second one's module options (validation policy, input format,
461
- * page-size ceiling) shadow the first's, and the app-wide interceptor is registered twice. There
462
- * is no moment at module-definition time when this module could see whether you have called it.
463
- *
464
- * Only the core is shared. The console's adapter never is: `RunFilter` names its own via
465
- * `@Filterable({ adapter })`, so your global adapter (your ORM's) keeps answering for your filters
466
- * and the run gateway answers for the console's, in the same process.
467
- */
468
- filterModule?: 'bootstrap' | 'host';
469
458
  }
470
459
  /**
471
460
  * Async variant of {@link DurableDashboardOptions}. The mount paths and `guards` stay static (the
@@ -480,8 +469,6 @@ interface DurableDashboardAsyncOptions {
480
469
  apiBasePath?: string;
481
470
  guards?: Type<CanActivate>[];
482
471
  imports?: DynamicModule['imports'];
483
- /** See {@link DurableDashboardOptions.filterModule}. */
484
- filterModule?: 'bootstrap' | 'host';
485
472
  /** Providers injected into `useDashboardAuth`, in order. Shared with a `guards` class's own deps. */
486
473
  inject?: Array<InjectionToken | OptionalFactoryDependency>;
487
474
  /** Build the `dashboardAuth` config from injected deps (or `undefined` to leave the console open). */
@@ -505,8 +492,6 @@ declare class DurableApiModule {
505
492
  * (true whenever `dashboardAuth` was set, or unconditionally for `forRootAsync`, where it's
506
493
  * resolved at runtime and is a no-op if it ends up unconfigured). */
507
494
  authMayBeConfigured: boolean;
508
- /** See {@link DurableDashboardOptions.filterModule}. */
509
- filterModule?: 'bootstrap' | 'host';
510
495
  }): DynamicModule;
511
496
  }
512
497
  /**
@@ -220,8 +220,8 @@ DashboardService = _ts_decorate([
220
220
  ], DashboardService);
221
221
 
222
222
  // src/server/durable-api.controller.ts
223
- import { ApplyFilter, FilterRunner } from "@dudousxd/nestjs-filter";
224
- import { Body, Controller, Get, Header, NotFoundException, Param, Post, Query, Sse } from "@nestjs/common";
223
+ import { ApplyFilter, ApplyFilterInterceptor, FilterRunner } from "@dudousxd/nestjs-filter";
224
+ import { Body, Controller, Get, Header, NotFoundException, Param, Post, Query, Sse, UseInterceptors } from "@nestjs/common";
225
225
 
226
226
  // src/server/durable-run.ts
227
227
  var DurableRun = class {
@@ -1190,6 +1190,7 @@ _ts_decorate4([
1190
1190
  ], DurableApiController.prototype, "update", null);
1191
1191
  DurableApiController = _ts_decorate4([
1192
1192
  Controller(),
1193
+ UseInterceptors(ApplyFilterInterceptor),
1193
1194
  _ts_metadata4("design:type", Function),
1194
1195
  _ts_metadata4("design:paramtypes", [
1195
1196
  typeof DashboardService === "undefined" ? Object : DashboardService,
@@ -2138,9 +2139,9 @@ DurableAuthController = _ts_decorate8([
2138
2139
 
2139
2140
  // src/server/durable-dashboard.module.ts
2140
2141
  import "reflect-metadata";
2141
- import { FilterModule } from "@dudousxd/nestjs-filter";
2142
+ import { ApplyFilterInterceptor as ApplyFilterInterceptor2, FilterRunner as FilterRunner2 } from "@dudousxd/nestjs-filter";
2142
2143
  import { Module } from "@nestjs/common";
2143
- import { RouterModule } from "@nestjs/core";
2144
+ import { ModuleRef, RouterModule } from "@nestjs/core";
2144
2145
 
2145
2146
  // src/server/durable-session.guard.ts
2146
2147
  import { Inject as Inject5, Injectable as Injectable4, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
@@ -2286,25 +2287,38 @@ var DurableApiModule = class _DurableApiModule {
2286
2287
  return {
2287
2288
  module: _DurableApiModule,
2288
2289
  imports: [
2289
- ...options.imports ?? [],
2290
- // `validation: 'off'`: the run filter's inputs are validated by its own translation — every
2291
- // field/operator pair either maps onto a `RunQuery` predicate or is rejected by name — so
2292
- // there is nothing left for class-validator to check, and requiring it would put a peer
2293
- // dependency on every consumer of this dashboard for no gain.
2294
- ...options.filterModule === "host" ? [] : [
2295
- FilterModule.forRoot({
2296
- validation: "off"
2297
- })
2298
- ]
2290
+ ...options.imports ?? []
2299
2291
  ],
2300
2292
  controllers: [
2301
2293
  DurableApiController
2302
2294
  ],
2303
2295
  providers: [
2304
2296
  DashboardService,
2305
- // The adapter is bound to its own token (never to the global `FILTER_ADAPTER`), which is
2306
- // what lets the console's filter and the host app's own filters run on different backends
2307
- // in one process — see `RunFilter`'s `@Filterable({ adapter })`.
2297
+ // `@dudousxd/nestjs-filter` is wired PRIVATELY here rather than through
2298
+ // `FilterModule.forRoot()`, which is a global registration. A library calling that would
2299
+ // fight the host app over one set of module options and register a second app-wide
2300
+ // interceptor — and it cannot tell at module-definition time whether the host already
2301
+ // called it. Everything below is scoped to this module, so the console composes with an app
2302
+ // that uses the filter library, and with one that has never heard of it, identically.
2303
+ //
2304
+ // `validation: 'off'`: the run filter's inputs are validated by their own translation —
2305
+ // every field/operator pair either maps onto a `RunQuery` predicate or is rejected by
2306
+ // name — so there is nothing left for class-validator to check, and requiring it would put
2307
+ // a peer dependency on every consumer of this dashboard for no gain.
2308
+ //
2309
+ // The `null` adapter is the GLOBAL one, deliberately absent: `RunFilter` names its own via
2310
+ // `@Filterable({ adapter })`, so the console runs on the durable run gateway while the host
2311
+ // app's filters keep running on whatever adapter it registered.
2312
+ {
2313
+ provide: FilterRunner2,
2314
+ useFactory: /* @__PURE__ */ __name((moduleRef) => new FilterRunner2(moduleRef, {
2315
+ validation: "off"
2316
+ }, null), "useFactory"),
2317
+ inject: [
2318
+ ModuleRef
2319
+ ]
2320
+ },
2321
+ ApplyFilterInterceptor2,
2308
2322
  RunQueryAdapter,
2309
2323
  {
2310
2324
  provide: RUN_QUERY_ADAPTER,
@@ -2362,9 +2376,6 @@ var DurableDashboardModule = class _DurableDashboardModule {
2362
2376
  ...options.guards ? {
2363
2377
  guards: options.guards
2364
2378
  } : {},
2365
- ...options.filterModule ? {
2366
- filterModule: options.filterModule
2367
- } : {},
2368
2379
  authProvider,
2369
2380
  authMayBeConfigured
2370
2381
  }),