@nextage/nx-frame-be 1.0.41 → 1.0.43
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/build/common/constants.js +1 -1
- package/build/common/graphql/__test__/registry.test.d.ts +1 -0
- package/build/common/graphql/__test__/registry.test.js +49 -0
- package/build/common/graphql/index.d.ts +1 -0
- package/build/common/graphql/index.js +1 -0
- package/build/common/graphql/registry.d.ts +47 -0
- package/build/common/graphql/registry.js +65 -0
- package/build/common/types.d.ts +13 -0
- package/package.json +1 -1
|
@@ -18,7 +18,7 @@ exports.APP = {
|
|
|
18
18
|
dataScr: process.env.SECRET,
|
|
19
19
|
nxPubSub: new pubsub_manager_1.PubSubManager(),
|
|
20
20
|
shutdownMng: new shutdown_manager_1.ShutdownManager(),
|
|
21
|
-
config: { endpoint: {}, email: {}, jwt: {}, aws: {}, mongo: {}, logging: {}, invite: {}, msg: {} }
|
|
21
|
+
config: { endpoint: {}, email: {}, jwt: {}, aws: {}, mongo: {}, logging: {}, invite: {}, msg: {}, app: {} }
|
|
22
22
|
};
|
|
23
23
|
exports.FILE_CONTENT_TYPES = {
|
|
24
24
|
none: '',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const coded_entity_controller_1 = require("../../models/coded-entity.controller");
|
|
4
|
+
const loader_1 = require("../loader");
|
|
5
|
+
const registry_1 = require("../registry");
|
|
6
|
+
/**
|
|
7
|
+
* `SchemaRegistry` defers `generateSchema`/`loadSchema` until `apply`, so module
|
|
8
|
+
* LOADING is decoupled from schema MUTATION. These tests assert the deferral,
|
|
9
|
+
* the single-shot application and the reset semantics used for test isolation.
|
|
10
|
+
*/
|
|
11
|
+
describe('SchemaRegistry', () => {
|
|
12
|
+
afterEach(() => registry_1.schemaRegistry.reset());
|
|
13
|
+
it('starts empty', () => {
|
|
14
|
+
expect(registry_1.schemaRegistry.count).toBe(0);
|
|
15
|
+
});
|
|
16
|
+
it('defers registerSchema until apply', () => {
|
|
17
|
+
const marker = 'registryProbeField: String';
|
|
18
|
+
registry_1.schemaRegistry.registerSchema({ typeDefs: { query: marker } });
|
|
19
|
+
// registration is recorded but NOT yet folded into mainSchema
|
|
20
|
+
expect(registry_1.schemaRegistry.count).toBe(1);
|
|
21
|
+
expect(loader_1.mainSchema.typeDefs.query).not.toContain('registryProbeField');
|
|
22
|
+
registry_1.schemaRegistry.apply();
|
|
23
|
+
expect(loader_1.mainSchema.typeDefs.query).toContain('registryProbeField');
|
|
24
|
+
});
|
|
25
|
+
it('defers register (controller) until apply', () => {
|
|
26
|
+
const params = {
|
|
27
|
+
fields: { type: 'id: String', query: 'code: String', input: 'code: String' }
|
|
28
|
+
};
|
|
29
|
+
registry_1.schemaRegistry.register(coded_entity_controller_1.ceCtrl, params);
|
|
30
|
+
// the CRUD query name is generated by generateSchema at apply time only
|
|
31
|
+
expect(registry_1.schemaRegistry.count).toBe(1);
|
|
32
|
+
expect(loader_1.mainSchema.typeDefs.query).not.toContain('codedEntityList');
|
|
33
|
+
registry_1.schemaRegistry.apply();
|
|
34
|
+
expect(loader_1.mainSchema.typeDefs.query).toContain('codedEntityList');
|
|
35
|
+
});
|
|
36
|
+
it('reset clears every registration', () => {
|
|
37
|
+
registry_1.schemaRegistry.registerSchema({ typeDefs: { query: 'a: String' } });
|
|
38
|
+
registry_1.schemaRegistry.registerSchema({ typeDefs: { query: 'b: String' } });
|
|
39
|
+
expect(registry_1.schemaRegistry.count).toBe(2);
|
|
40
|
+
registry_1.schemaRegistry.reset();
|
|
41
|
+
expect(registry_1.schemaRegistry.count).toBe(0);
|
|
42
|
+
});
|
|
43
|
+
it('exposes a class for isolated instances', () => {
|
|
44
|
+
const local = new registry_1.SchemaRegistry();
|
|
45
|
+
local.registerSchema({ typeDefs: { query: 'c: String' } });
|
|
46
|
+
expect(local.count).toBe(1);
|
|
47
|
+
expect(registry_1.schemaRegistry.count).toBe(0);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -17,5 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./directives"), exports);
|
|
18
18
|
__exportStar(require("./loader"), exports);
|
|
19
19
|
__exportStar(require("./generator"), exports);
|
|
20
|
+
__exportStar(require("./registry"), exports);
|
|
20
21
|
__exportStar(require("./utils"), exports);
|
|
21
22
|
//export * from './scalars';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BaseController } from '../base/base.controller';
|
|
2
|
+
import { NxGraphQLSchemaData, NxGraphQLSchemaExtension } from './interfaces';
|
|
3
|
+
/**
|
|
4
|
+
* Deferred GraphQL schema-assembly registry.
|
|
5
|
+
*
|
|
6
|
+
* Historically every nx-app GraphQL leaf mutated the global `mainSchema` at
|
|
7
|
+
* import time by calling `generateSchema`/`loadSchema` as a module side-effect.
|
|
8
|
+
* That coupled module LOADING (which files get imported, and in what order) with
|
|
9
|
+
* schema MUTATION, and left the registered set invisible and non-resettable.
|
|
10
|
+
*
|
|
11
|
+
* With this registry a leaf instead REGISTERS its module — a controller plus a
|
|
12
|
+
* schema extension, or a raw typeDefs/resolvers block — deferring the actual
|
|
13
|
+
* `generateSchema`/`loadSchema` call. The bootstrap `graphql` phase discovers and
|
|
14
|
+
* imports the leaves (which call {@link register}/{@link registerSchema}) and then
|
|
15
|
+
* calls {@link apply} ONCE to fold every module into `mainSchema`.
|
|
16
|
+
*
|
|
17
|
+
* Benefits: loading is order-independent (filesystem discovery), mutation is a
|
|
18
|
+
* single explicit logged step, and the registered set is inspectable ({@link count})
|
|
19
|
+
* and resettable ({@link reset}) for test isolation.
|
|
20
|
+
*/
|
|
21
|
+
export declare class SchemaRegistry {
|
|
22
|
+
private deferred;
|
|
23
|
+
/**
|
|
24
|
+
* Register a controller-backed module. Mirrors {@link generateSchema}'s
|
|
25
|
+
* signature verbatim; the call is deferred until {@link apply}.
|
|
26
|
+
*/
|
|
27
|
+
register<T extends BaseController<any, any, any>>(controller: T, schema?: NxGraphQLSchemaExtension, mergeCodedEntity?: boolean, readOnly?: boolean): void;
|
|
28
|
+
/**
|
|
29
|
+
* Register a raw typeDefs/resolvers block (no controller). Mirrors
|
|
30
|
+
* {@link loadSchema}; the call is deferred until {@link apply}.
|
|
31
|
+
*/
|
|
32
|
+
registerSchema(data: NxGraphQLSchemaData): void;
|
|
33
|
+
/**
|
|
34
|
+
* Fold every registered module into the global `mainSchema`. Call ONCE from
|
|
35
|
+
* the bootstrap `graphql` phase, after all leaves have been imported.
|
|
36
|
+
*/
|
|
37
|
+
apply(): void;
|
|
38
|
+
/** Clear all registrations (test isolation). */
|
|
39
|
+
reset(): void;
|
|
40
|
+
/** Number of modules registered so far. */
|
|
41
|
+
get count(): number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Process-wide GraphQL schema registry singleton. nx-app leaves import this and
|
|
45
|
+
* call `register`/`registerSchema`; the bootstrap `graphql` phase calls `apply`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const schemaRegistry: SchemaRegistry;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schemaRegistry = exports.SchemaRegistry = void 0;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const generator_1 = require("./generator");
|
|
6
|
+
const loader_1 = require("./loader");
|
|
7
|
+
/**
|
|
8
|
+
* Deferred GraphQL schema-assembly registry.
|
|
9
|
+
*
|
|
10
|
+
* Historically every nx-app GraphQL leaf mutated the global `mainSchema` at
|
|
11
|
+
* import time by calling `generateSchema`/`loadSchema` as a module side-effect.
|
|
12
|
+
* That coupled module LOADING (which files get imported, and in what order) with
|
|
13
|
+
* schema MUTATION, and left the registered set invisible and non-resettable.
|
|
14
|
+
*
|
|
15
|
+
* With this registry a leaf instead REGISTERS its module — a controller plus a
|
|
16
|
+
* schema extension, or a raw typeDefs/resolvers block — deferring the actual
|
|
17
|
+
* `generateSchema`/`loadSchema` call. The bootstrap `graphql` phase discovers and
|
|
18
|
+
* imports the leaves (which call {@link register}/{@link registerSchema}) and then
|
|
19
|
+
* calls {@link apply} ONCE to fold every module into `mainSchema`.
|
|
20
|
+
*
|
|
21
|
+
* Benefits: loading is order-independent (filesystem discovery), mutation is a
|
|
22
|
+
* single explicit logged step, and the registered set is inspectable ({@link count})
|
|
23
|
+
* and resettable ({@link reset}) for test isolation.
|
|
24
|
+
*/
|
|
25
|
+
class SchemaRegistry {
|
|
26
|
+
constructor() {
|
|
27
|
+
this.deferred = [];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Register a controller-backed module. Mirrors {@link generateSchema}'s
|
|
31
|
+
* signature verbatim; the call is deferred until {@link apply}.
|
|
32
|
+
*/
|
|
33
|
+
register(controller, schema = {}, mergeCodedEntity = false, readOnly = false) {
|
|
34
|
+
this.deferred.push(() => (0, generator_1.generateSchema)(controller, schema, mergeCodedEntity, readOnly));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Register a raw typeDefs/resolvers block (no controller). Mirrors
|
|
38
|
+
* {@link loadSchema}; the call is deferred until {@link apply}.
|
|
39
|
+
*/
|
|
40
|
+
registerSchema(data) {
|
|
41
|
+
this.deferred.push(() => (0, loader_1.loadSchema)(data));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Fold every registered module into the global `mainSchema`. Call ONCE from
|
|
45
|
+
* the bootstrap `graphql` phase, after all leaves have been imported.
|
|
46
|
+
*/
|
|
47
|
+
apply() {
|
|
48
|
+
this.deferred.forEach(run => run());
|
|
49
|
+
constants_1.APP.logger.info(`🧩 GraphQL registry: applied ${this.deferred.length} schema module(s)`);
|
|
50
|
+
}
|
|
51
|
+
/** Clear all registrations (test isolation). */
|
|
52
|
+
reset() {
|
|
53
|
+
this.deferred = [];
|
|
54
|
+
}
|
|
55
|
+
/** Number of modules registered so far. */
|
|
56
|
+
get count() {
|
|
57
|
+
return this.deferred.length;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.SchemaRegistry = SchemaRegistry;
|
|
61
|
+
/**
|
|
62
|
+
* Process-wide GraphQL schema registry singleton. nx-app leaves import this and
|
|
63
|
+
* call `register`/`registerSchema`; the bootstrap `graphql` phase calls `apply`.
|
|
64
|
+
*/
|
|
65
|
+
exports.schemaRegistry = new SchemaRegistry();
|
package/build/common/types.d.ts
CHANGED
|
@@ -42,7 +42,20 @@ export type AppConfig = {
|
|
|
42
42
|
mongo: AppMongoDB;
|
|
43
43
|
invite: AppInvitation;
|
|
44
44
|
logging: AppLogging;
|
|
45
|
+
app: AppCustomConfig;
|
|
45
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* Application-specific configuration slot.
|
|
49
|
+
*
|
|
50
|
+
* Intentionally EMPTY in the framework: each consuming application augments this
|
|
51
|
+
* interface (declaration merging: `declare module '@nextage/nx-frame-be'`) to
|
|
52
|
+
* add its own strongly-typed settings, and populates `APP.config.app` at bootstrap
|
|
53
|
+
* (after env is read). This keeps CORE config (`endpoint`, `jwt`, `mongo`, …) in
|
|
54
|
+
* the framework while APP-ONLY settings live here — typed by the app, not by env
|
|
55
|
+
* reads scattered across the codebase.
|
|
56
|
+
*/
|
|
57
|
+
export interface AppCustomConfig {
|
|
58
|
+
}
|
|
46
59
|
export type AppMongoDB = {
|
|
47
60
|
auth?: {
|
|
48
61
|
us: string;
|