@servicelabsco/slabs-access-manager 1.0.67 → 1.0.69

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.
Files changed (198) hide show
  1. package/dist/access/controllers/business.report.controller.js.map +1 -1
  2. package/dist/access/controllers/dashboard.report.controller.js +2 -1
  3. package/dist/access/controllers/dashboard.report.controller.js.map +1 -1
  4. package/dist/access/controllers/index.d.ts +1 -0
  5. package/dist/access/controllers/index.js +1 -0
  6. package/dist/access/controllers/index.js.map +1 -1
  7. package/dist/access/controllers/oauth.as.controller.d.ts +1 -0
  8. package/dist/access/controllers/oauth.as.controller.js +24 -0
  9. package/dist/access/controllers/oauth.as.controller.js.map +1 -1
  10. package/dist/access/controllers/report.view.controller.d.ts +101 -0
  11. package/dist/access/controllers/report.view.controller.js +66 -0
  12. package/dist/access/controllers/report.view.controller.js.map +1 -0
  13. package/dist/access/controllers/whoami.controller.js +3 -2
  14. package/dist/access/controllers/whoami.controller.js.map +1 -1
  15. package/dist/access/dtos/index.d.ts +1 -0
  16. package/dist/access/dtos/index.js +1 -0
  17. package/dist/access/dtos/index.js.map +1 -1
  18. package/dist/access/dtos/report.view.query.dto.d.ts +23 -0
  19. package/dist/access/dtos/report.view.query.dto.js +56 -0
  20. package/dist/access/dtos/report.view.query.dto.js.map +1 -0
  21. package/dist/access/es6.classes.d.ts +24 -14
  22. package/dist/access/es6.classes.js +42 -25
  23. package/dist/access/es6.classes.js.map +1 -1
  24. package/dist/access/jobs/form.script.job.js +1 -1
  25. package/dist/access/libraries/index.d.ts +1 -0
  26. package/dist/access/libraries/index.js +1 -0
  27. package/dist/access/libraries/index.js.map +1 -1
  28. package/dist/access/libraries/process.form.script.list.js.map +1 -1
  29. package/dist/access/libraries/report.view.query.compiler.d.ts +163 -0
  30. package/dist/access/libraries/report.view.query.compiler.js +399 -0
  31. package/dist/access/libraries/report.view.query.compiler.js.map +1 -0
  32. package/dist/access/services/credential.resolve.service.js +18 -3
  33. package/dist/access/services/credential.resolve.service.js.map +1 -1
  34. package/dist/access/services/es6.jobs.service.d.ts +3 -3
  35. package/dist/access/services/es6.jobs.service.js +5 -5
  36. package/dist/access/services/es6.jobs.service.js.map +1 -1
  37. package/dist/access/services/index.d.ts +1 -0
  38. package/dist/access/services/index.js +1 -0
  39. package/dist/access/services/index.js.map +1 -1
  40. package/dist/access/services/oauth.as.service.d.ts +8 -5
  41. package/dist/access/services/oauth.as.service.js +92 -48
  42. package/dist/access/services/oauth.as.service.js.map +1 -1
  43. package/dist/access/services/report.view.service.d.ts +111 -0
  44. package/dist/access/services/report.view.service.js +234 -0
  45. package/dist/access/services/report.view.service.js.map +1 -0
  46. package/dist/accessUtility/access.utility.module.js +2 -2
  47. package/dist/accessUtility/access.utility.module.js.map +1 -1
  48. package/dist/accessUtility/es6.classes.d.ts +1 -1
  49. package/dist/accessUtility/es6.classes.js +2 -2
  50. package/dist/accessUtility/es6.classes.js.map +1 -1
  51. package/dist/accessUtility/index.d.ts +1 -1
  52. package/dist/accessUtility/index.js +1 -1
  53. package/dist/accessUtility/index.js.map +1 -1
  54. package/dist/accessUtility/{types/bulk.upload.item.record.js → interfaces/bulk.upload.item.record.interface.js} +1 -1
  55. package/dist/accessUtility/interfaces/bulk.upload.item.record.interface.js.map +1 -0
  56. package/dist/accessUtility/interfaces/index.d.ts +1 -0
  57. package/dist/accessUtility/interfaces/index.js +18 -0
  58. package/dist/accessUtility/interfaces/index.js.map +1 -0
  59. package/dist/accessUtility/jobs/bulk.upload.column.match.job.js.map +1 -1
  60. package/dist/accessUtility/jobs/push.to.bulk.item.job.d.ts +1 -1
  61. package/dist/accessUtility/libraries/set.bulk.upload.log.file.js.map +1 -1
  62. package/dist/accessUtility/services/bulk.upload.item.store.d.ts +1 -1
  63. package/dist/accessUtility/services/bulk.upload.item.store.js.map +1 -1
  64. package/dist/app.module.js +2 -0
  65. package/dist/app.module.js.map +1 -1
  66. package/dist/config/entity.constants.d.ts +2 -2
  67. package/dist/config/entity.constants.js +2 -2
  68. package/dist/config/entity.constants.js.map +1 -1
  69. package/dist/config/mongo.config.d.ts +3 -0
  70. package/dist/config/mongo.config.js +16 -0
  71. package/dist/config/mongo.config.js.map +1 -0
  72. package/dist/config/source.hash.d.ts +1 -0
  73. package/dist/config/source.hash.js +1 -0
  74. package/dist/config/source.hash.js.map +1 -1
  75. package/dist/development/controllers/development.catalog.controller.d.ts +53 -0
  76. package/dist/development/controllers/development.catalog.controller.js +112 -0
  77. package/dist/development/controllers/development.catalog.controller.js.map +1 -0
  78. package/dist/development/controllers/index.d.ts +1 -0
  79. package/dist/development/controllers/index.js +1 -0
  80. package/dist/development/controllers/index.js.map +1 -1
  81. package/dist/development/development.module.js +2 -1
  82. package/dist/development/development.module.js.map +1 -1
  83. package/dist/development/dtos/column.catalog.attributes.dto.d.ts +10 -0
  84. package/dist/development/dtos/column.catalog.attributes.dto.js +58 -0
  85. package/dist/development/dtos/column.catalog.attributes.dto.js.map +1 -0
  86. package/dist/development/dtos/index.d.ts +2 -0
  87. package/dist/development/dtos/index.js +19 -0
  88. package/dist/development/dtos/index.js.map +1 -0
  89. package/dist/development/dtos/material.view.catalog.attributes.dto.d.ts +25 -0
  90. package/dist/development/dtos/material.view.catalog.attributes.dto.js +114 -0
  91. package/dist/development/dtos/material.view.catalog.attributes.dto.js.map +1 -0
  92. package/dist/development/es6.classes.d.ts +10 -3
  93. package/dist/development/es6.classes.js +10 -3
  94. package/dist/development/es6.classes.js.map +1 -1
  95. package/dist/development/gates/index.d.ts +1 -0
  96. package/dist/{accessUtility/types → development/gates}/index.js +1 -1
  97. package/dist/development/gates/index.js.map +1 -0
  98. package/dist/development/gates/reporting.catalog.gate.d.ts +8 -0
  99. package/dist/development/gates/reporting.catalog.gate.js +39 -0
  100. package/dist/development/gates/reporting.catalog.gate.js.map +1 -0
  101. package/dist/development/index.d.ts +2 -0
  102. package/dist/development/index.js +2 -0
  103. package/dist/development/index.js.map +1 -1
  104. package/dist/development/services/admin.report.view.service.d.ts +92 -0
  105. package/dist/development/services/admin.report.view.service.js +459 -0
  106. package/dist/development/services/admin.report.view.service.js.map +1 -0
  107. package/dist/development/services/index.d.ts +1 -0
  108. package/dist/development/services/index.js +1 -0
  109. package/dist/development/services/index.js.map +1 -1
  110. package/dist/main.js +1 -1
  111. package/dist/main.js.map +1 -1
  112. package/dist/mcp/admin/tools/admin.tool.registry.js +14 -0
  113. package/dist/mcp/admin/tools/admin.tool.registry.js.map +1 -1
  114. package/dist/mcp/admin/tools/catalog/admin.catalog.validate.tool.d.ts +16 -0
  115. package/dist/mcp/admin/tools/catalog/admin.catalog.validate.tool.js +22 -0
  116. package/dist/mcp/admin/tools/catalog/admin.catalog.validate.tool.js.map +1 -0
  117. package/dist/mcp/admin/tools/catalog/admin.column.describe.tool.d.ts +30 -0
  118. package/dist/mcp/admin/tools/catalog/admin.column.describe.tool.js +37 -0
  119. package/dist/mcp/admin/tools/catalog/admin.column.describe.tool.js.map +1 -0
  120. package/dist/mcp/admin/tools/catalog/admin.view.columns.sync.tool.d.ts +22 -0
  121. package/dist/mcp/admin/tools/catalog/admin.view.columns.sync.tool.js +31 -0
  122. package/dist/mcp/admin/tools/catalog/admin.view.columns.sync.tool.js.map +1 -0
  123. package/dist/mcp/admin/tools/catalog/admin.view.register.tool.d.ts +22 -0
  124. package/dist/mcp/admin/tools/catalog/admin.view.register.tool.js +28 -0
  125. package/dist/mcp/admin/tools/catalog/admin.view.register.tool.js.map +1 -0
  126. package/dist/mcp/admin/tools/catalog/admin.view.sample.tool.d.ts +21 -0
  127. package/dist/mcp/admin/tools/catalog/admin.view.sample.tool.js +32 -0
  128. package/dist/mcp/admin/tools/catalog/admin.view.sample.tool.js.map +1 -0
  129. package/dist/mcp/admin/tools/catalog/admin.view.update.tool.d.ts +22 -0
  130. package/dist/mcp/admin/tools/catalog/admin.view.update.tool.js +29 -0
  131. package/dist/mcp/admin/tools/catalog/admin.view.update.tool.js.map +1 -0
  132. package/dist/mcp/admin/tools/catalog/admin.views.list.tool.d.ts +10 -0
  133. package/dist/mcp/admin/tools/catalog/admin.views.list.tool.js +20 -0
  134. package/dist/mcp/admin/tools/catalog/admin.views.list.tool.js.map +1 -0
  135. package/dist/mcp/admin/tools/catalog/index.d.ts +7 -0
  136. package/dist/mcp/admin/tools/catalog/index.js +24 -0
  137. package/dist/mcp/admin/tools/catalog/index.js.map +1 -0
  138. package/dist/mcp/admin/tools/form_script/form.script.create.tool.js.map +1 -1
  139. package/dist/mcp/admin/tools/form_script/form.script.list.tool.js.map +1 -1
  140. package/dist/mcp/admin/tools/form_script/form.script.update.tool.js.map +1 -1
  141. package/dist/mcp/admin/tools/index.d.ts +1 -0
  142. package/dist/mcp/admin/tools/index.js +1 -0
  143. package/dist/mcp/admin/tools/index.js.map +1 -1
  144. package/dist/mcp/admin/tools/report/report.create.tool.js.map +1 -1
  145. package/dist/mcp/admin/tools/report/report.update.tool.js.map +1 -1
  146. package/dist/mcp/auth/mcp.idempotency.store.js +3 -1
  147. package/dist/mcp/auth/mcp.idempotency.store.js.map +1 -1
  148. package/dist/mcp/catalog/assert.valid.catalog.d.ts +3 -0
  149. package/dist/mcp/catalog/assert.valid.catalog.js +2 -0
  150. package/dist/mcp/catalog/assert.valid.catalog.js.map +1 -1
  151. package/dist/mcp/es6.classes.d.ts +54 -8
  152. package/dist/mcp/es6.classes.js +74 -12
  153. package/dist/mcp/es6.classes.js.map +1 -1
  154. package/dist/mcp/http/mcp.http.module.js +5 -2
  155. package/dist/mcp/http/mcp.http.module.js.map +1 -1
  156. package/dist/mcp/index.d.ts +2 -0
  157. package/dist/mcp/index.js +2 -0
  158. package/dist/mcp/index.js.map +1 -1
  159. package/dist/mcp/logging/index.d.ts +3 -0
  160. package/dist/mcp/logging/index.js +20 -0
  161. package/dist/mcp/logging/index.js.map +1 -0
  162. package/dist/mcp/logging/mcp.call.log.interceptor.d.ts +16 -0
  163. package/dist/mcp/logging/mcp.call.log.interceptor.js +140 -0
  164. package/dist/mcp/logging/mcp.call.log.interceptor.js.map +1 -0
  165. package/dist/mcp/logging/mcp.call.log.writer.d.ts +11 -0
  166. package/dist/mcp/logging/mcp.call.log.writer.js +62 -0
  167. package/dist/mcp/logging/mcp.call.log.writer.js.map +1 -0
  168. package/dist/mcp/logging/sanitize.mcp.call.log.d.ts +44 -0
  169. package/dist/mcp/logging/sanitize.mcp.call.log.js +112 -0
  170. package/dist/mcp/logging/sanitize.mcp.call.log.js.map +1 -0
  171. package/dist/mcp/mcp.module.d.ts +1 -1
  172. package/dist/mcp/mcp.module.js.map +1 -1
  173. package/dist/mcp/mentities/index.d.ts +1 -0
  174. package/dist/mcp/mentities/index.js +18 -0
  175. package/dist/mcp/mentities/index.js.map +1 -0
  176. package/dist/mcp/mentities/mcp.call.log.mentity.d.ts +17 -0
  177. package/dist/mcp/mentities/mcp.call.log.mentity.js +79 -0
  178. package/dist/mcp/mentities/mcp.call.log.mentity.js.map +1 -0
  179. package/dist/mcp/tools/index.d.ts +3 -0
  180. package/dist/mcp/tools/index.js +3 -0
  181. package/dist/mcp/tools/index.js.map +1 -1
  182. package/dist/mcp/tools/reports.run.tool.js.map +1 -1
  183. package/dist/mcp/tools/tool.registry.js +4 -21
  184. package/dist/mcp/tools/tool.registry.js.map +1 -1
  185. package/dist/mcp/tools/view.describe.tool.d.ts +17 -0
  186. package/dist/mcp/tools/view.describe.tool.js +23 -0
  187. package/dist/mcp/tools/view.describe.tool.js.map +1 -0
  188. package/dist/mcp/tools/view.query.tool.d.ts +75 -0
  189. package/dist/mcp/tools/view.query.tool.js +51 -0
  190. package/dist/mcp/tools/view.query.tool.js.map +1 -0
  191. package/dist/mcp/tools/views.list.tool.d.ts +10 -0
  192. package/dist/mcp/tools/views.list.tool.js +20 -0
  193. package/dist/mcp/tools/views.list.tool.js.map +1 -0
  194. package/package.json +2 -2
  195. package/dist/accessUtility/types/bulk.upload.item.record.js.map +0 -1
  196. package/dist/accessUtility/types/index.d.ts +0 -1
  197. package/dist/accessUtility/types/index.js.map +0 -1
  198. /package/dist/accessUtility/{types/bulk.upload.item.record.d.ts → interfaces/bulk.upload.item.record.interface.d.ts} +0 -0
@@ -0,0 +1,8 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { AdminReportViewService } from '../services/admin.report.view.service';
3
+ export declare class ReportingCatalogGate implements OnModuleInit {
4
+ private readonly service;
5
+ private readonly logger;
6
+ constructor(service: AdminReportViewService);
7
+ onModuleInit(): Promise<void>;
8
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var ReportingCatalogGate_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.ReportingCatalogGate = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const admin_report_view_service_1 = require("../services/admin.report.view.service");
16
+ let ReportingCatalogGate = ReportingCatalogGate_1 = class ReportingCatalogGate {
17
+ constructor(service) {
18
+ this.service = service;
19
+ this.logger = new common_1.Logger(ReportingCatalogGate_1.name);
20
+ }
21
+ async onModuleInit() {
22
+ try {
23
+ const result = await this.service.validate();
24
+ const views = Array.isArray(result?.views) ? result.views : [];
25
+ const dropped = views.filter((view) => view.dropped);
26
+ this.logger.log(`reporting catalog gate: ${views.length} view(s), dropped=${dropped.length}`);
27
+ }
28
+ catch (error) {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ this.logger.warn(`reporting catalog gate skipped: ${message}`);
31
+ }
32
+ }
33
+ };
34
+ exports.ReportingCatalogGate = ReportingCatalogGate;
35
+ exports.ReportingCatalogGate = ReportingCatalogGate = ReportingCatalogGate_1 = __decorate([
36
+ (0, common_1.Injectable)(),
37
+ __metadata("design:paramtypes", [admin_report_view_service_1.AdminReportViewService])
38
+ ], ReportingCatalogGate);
39
+ //# sourceMappingURL=reporting.catalog.gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporting.catalog.gate.js","sourceRoot":"","sources":["../../../src/development/gates/reporting.catalog.gate.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAkE;AAClE,qFAA+E;AAOxE,IAAM,oBAAoB,4BAA1B,MAAM,oBAAoB;IAG7B,YAA6B,OAA+B;QAA/B,YAAO,GAAP,OAAO,CAAwB;QAF3C,WAAM,GAAG,IAAI,eAAM,CAAC,sBAAoB,CAAC,IAAI,CAAC,CAAC;IAED,CAAC;IAEhE,KAAK,CAAC,YAAY;QACd,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAE,MAAc,EAAE,KAAK,CAAC,CAAC,CAAC,CAAE,MAAc,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAA2B,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,KAAK,CAAC,MAAM,qBAAqB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAClG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,OAAO,EAAE,CAAC,CAAC;QACnE,CAAC;IACL,CAAC;CACJ,CAAA;AAhBY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;qCAI6B,kDAAsB;GAHnD,oBAAoB,CAgBhC"}
@@ -1,5 +1,7 @@
1
1
  export * from './commands';
2
2
  export * from './controllers';
3
+ export * from './dtos';
4
+ export * from './gates';
3
5
  export * from './interfaces';
4
6
  export * from './middlewares';
5
7
  export * from './registries';
@@ -16,6 +16,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./commands"), exports);
18
18
  __exportStar(require("./controllers"), exports);
19
+ __exportStar(require("./dtos"), exports);
20
+ __exportStar(require("./gates"), exports);
19
21
  __exportStar(require("./interfaces"), exports);
20
22
  __exportStar(require("./middlewares"), exports);
21
23
  __exportStar(require("./registries"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/development/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAAA,gDAA8B;AAAA,+CAA6B;AAAA,gDAA8B;AAAA,+CAA6B;AAAA,6CAA2B;AAAA,uDAAoC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/development/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAAA,gDAA8B;AAAA,yCAAuB;AAAA,0CAAwB;AAAA,+CAA6B;AAAA,gDAA8B;AAAA,+CAA6B;AAAA,6CAA2B;AAAA,uDAAoC"}
@@ -0,0 +1,92 @@
1
+ import { MaterialViewEntity, SqlService } from '@servicelabsco/nestjs-utility-services';
2
+ export type CatalogFinding = string;
3
+ export type CatalogGateResult = {
4
+ table_name: string;
5
+ ok: boolean;
6
+ findings: CatalogFinding[];
7
+ agent_visible: boolean;
8
+ dropped?: boolean;
9
+ };
10
+ export type ColumnDescribePatch = {
11
+ name: string;
12
+ display_name?: string;
13
+ description?: string;
14
+ visibility?: boolean;
15
+ attributes?: Record<string, unknown>;
16
+ };
17
+ export type ColumnsSyncInput = {
18
+ table_name?: string;
19
+ source_type?: string;
20
+ source_id?: number;
21
+ name?: string;
22
+ };
23
+ export declare class AdminReportViewService {
24
+ private readonly sqlService;
25
+ private readonly logger;
26
+ constructor(sqlService: SqlService);
27
+ list(): Promise<{
28
+ views: Array<Record<string, unknown>>;
29
+ }>;
30
+ register(body: {
31
+ table_name?: string;
32
+ timing?: string;
33
+ active?: boolean;
34
+ attributes?: Record<string, unknown>;
35
+ }): Promise<MaterialViewEntity>;
36
+ update(tableName: string, body: {
37
+ timing?: string;
38
+ active?: boolean;
39
+ attributes?: Record<string, unknown>;
40
+ }): Promise<{
41
+ view: MaterialViewEntity;
42
+ gate: CatalogGateResult;
43
+ }>;
44
+ sample(tableName: string, limit?: number | string, offset?: number | string): Promise<{
45
+ table_name: string;
46
+ limit: number;
47
+ offset: number;
48
+ rows: any[];
49
+ }>;
50
+ columnsSync(input?: string | ColumnsSyncInput): Promise<{
51
+ table_name: string;
52
+ created: string[];
53
+ adopted: string[];
54
+ orphaned: string[];
55
+ }>;
56
+ private resolveView;
57
+ private upsertLiveColumn;
58
+ describeColumns(tableName: string, patches?: ColumnDescribePatch[]): Promise<{
59
+ table_name: string;
60
+ updated: string[];
61
+ missing: string[];
62
+ gate: CatalogGateResult;
63
+ }>;
64
+ validate(tableName?: string): Promise<CatalogGateResult | {
65
+ views: CatalogGateResult[];
66
+ }>;
67
+ private evaluate;
68
+ private parseViewAttributes;
69
+ private parseColumnAttributes;
70
+ private tryParseViewAttributes;
71
+ private tryParseColumnAttributes;
72
+ private formatErrors;
73
+ private applyViewDefaults;
74
+ private defaultCatalogName;
75
+ private tenancyColumn;
76
+ private asViewRow;
77
+ private requireRegisteredView;
78
+ private assertTableName;
79
+ private quoteIdent;
80
+ private clampLimit;
81
+ private clampOffset;
82
+ private assertRelationExists;
83
+ private relationExists;
84
+ private boundReadFirst;
85
+ private loadLiveColumns;
86
+ private normalizeLiveColumn;
87
+ private resolveTypeId;
88
+ private loadLiveColumnsSafe;
89
+ private columnTypeMapping;
90
+ private displayName;
91
+ private hasEnumMap;
92
+ }
@@ -0,0 +1,459 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var AdminReportViewService_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.AdminReportViewService = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const nestjs_utility_services_1 = require("@servicelabsco/nestjs-utility-services");
16
+ const class_transformer_1 = require("class-transformer");
17
+ const class_validator_1 = require("class-validator");
18
+ const typeorm_1 = require("typeorm");
19
+ const SourceHash = require("../../config/source.hash");
20
+ const column_catalog_attributes_dto_1 = require("../dtos/column.catalog.attributes.dto");
21
+ const material_view_catalog_attributes_dto_1 = require("../dtos/material.view.catalog.attributes.dto");
22
+ const SAMPLE_CAP = 100;
23
+ const DEFAULT_SAMPLE_LIMIT = 20;
24
+ const DEFAULT_TENANCY = 'business_id';
25
+ const DEFAULT_TIMING = '0 * * * *';
26
+ let AdminReportViewService = AdminReportViewService_1 = class AdminReportViewService {
27
+ constructor(sqlService) {
28
+ this.sqlService = sqlService;
29
+ this.logger = new common_1.Logger(AdminReportViewService_1.name);
30
+ }
31
+ async list() {
32
+ const rows = await nestjs_utility_services_1.MaterialViewEntity.find({ order: { table_name: 'ASC' } });
33
+ const views = [];
34
+ for (const row of rows) {
35
+ const gate = await this.evaluate(row, { persistDrop: false });
36
+ views.push({
37
+ id: row.id,
38
+ table_name: row.table_name,
39
+ active: row.active,
40
+ timing: row.timing,
41
+ last_run_time: row.last_run_time,
42
+ attributes: row.attributes || {},
43
+ gate: { ok: gate.ok, findings: gate.findings },
44
+ });
45
+ }
46
+ return { views };
47
+ }
48
+ async register(body) {
49
+ const tableName = this.assertTableName(body?.table_name);
50
+ await this.assertRelationExists(tableName);
51
+ const attributes = this.parseViewAttributes(body?.attributes || {}, true);
52
+ this.applyViewDefaults(tableName, attributes);
53
+ if (attributes.agent_visible) {
54
+ const probe = this.asViewRow({ table_name: tableName, attributes });
55
+ const gate = await this.evaluate(probe, { persistDrop: false });
56
+ if (!gate.ok) {
57
+ throw new nestjs_utility_services_1.OperationException(`Cannot set agent_visible: ${gate.findings.join('; ')}`);
58
+ }
59
+ }
60
+ const row = await nestjs_utility_services_1.MaterialViewEntity.firstOrNew({ table_name: tableName });
61
+ row.table_name = tableName;
62
+ row.timing = body?.timing || row.timing || DEFAULT_TIMING;
63
+ row.active = body?.active === undefined ? (row.active ?? true) : Boolean(body.active);
64
+ row.attributes = { ...(row.attributes || {}), ...attributes };
65
+ await row.save();
66
+ return row;
67
+ }
68
+ async update(tableName, body) {
69
+ const row = await this.requireRegisteredView(tableName);
70
+ const patch = this.parseViewAttributes(body?.attributes || {}, true);
71
+ const next = { ...(row.attributes || {}), ...patch };
72
+ if (body?.timing !== undefined)
73
+ row.timing = body.timing;
74
+ if (body?.active !== undefined)
75
+ row.active = Boolean(body.active);
76
+ row.attributes = next;
77
+ const turningOn = Boolean(next.agent_visible);
78
+ const gate = await this.evaluate(row, { persistDrop: false });
79
+ if (turningOn && !gate.ok) {
80
+ throw new nestjs_utility_services_1.OperationException(`Cannot set agent_visible: ${gate.findings.join('; ')}`);
81
+ }
82
+ await row.save();
83
+ return { view: row, gate };
84
+ }
85
+ async sample(tableName, limit, offset) {
86
+ const row = await this.requireRegisteredView(tableName);
87
+ const cap = this.clampLimit(limit);
88
+ const skip = this.clampOffset(offset);
89
+ const ident = this.quoteIdent(row.table_name);
90
+ const rows = await this.sqlService.boundRead(`SELECT * FROM ${ident} LIMIT $1 OFFSET $2`, [cap, skip]);
91
+ return {
92
+ table_name: row.table_name,
93
+ limit: cap,
94
+ offset: skip,
95
+ rows: Array.isArray(rows) ? rows : [],
96
+ };
97
+ }
98
+ async columnsSync(input = {}) {
99
+ const args = typeof input === 'string' ? { table_name: input } : input || {};
100
+ const sourceType = args.source_type || SourceHash.materialView;
101
+ if (sourceType !== SourceHash.materialView) {
102
+ throw new nestjs_utility_services_1.OperationException('source_type must be the material-view hash 6cc76494999951a1ac3631ca815c1786');
103
+ }
104
+ const row = await this.resolveView(args);
105
+ await this.assertRelationExists(row.table_name);
106
+ const live = await this.loadLiveColumns(row.table_name);
107
+ const typeMap = await this.columnTypeMapping();
108
+ if (args.name) {
109
+ const liveCol = live.find((column) => column.column_name === args.name);
110
+ if (!liveCol)
111
+ throw new common_1.BadRequestException(`column '${args.name}' is not on ${row.table_name}`);
112
+ const created = await this.upsertLiveColumn(row, liveCol, typeMap, sourceType);
113
+ return {
114
+ table_name: row.table_name,
115
+ created: created ? [args.name] : [],
116
+ adopted: created ? [] : [args.name],
117
+ orphaned: [],
118
+ };
119
+ }
120
+ const existing = await nestjs_utility_services_1.ColumnEntity.find({
121
+ where: { source_type: sourceType, source_id: row.id },
122
+ });
123
+ const byName = new Map(existing.map((column) => [column.name, column]));
124
+ const liveNames = new Set(live.map((column) => column.column_name));
125
+ const created = [];
126
+ const adopted = [];
127
+ for (const liveCol of live) {
128
+ const isNew = await this.upsertLiveColumn(row, liveCol, typeMap, sourceType);
129
+ if (isNew)
130
+ created.push(liveCol.column_name);
131
+ else
132
+ adopted.push(liveCol.column_name);
133
+ byName.delete(liveCol.column_name);
134
+ }
135
+ const orphaned = [...byName.keys()].filter((name) => !liveNames.has(name));
136
+ return { table_name: row.table_name, created, adopted, orphaned };
137
+ }
138
+ async resolveView(args) {
139
+ if (args.source_id) {
140
+ const row = await nestjs_utility_services_1.MaterialViewEntity.findOne({ where: { id: args.source_id } });
141
+ if (!row)
142
+ throw new nestjs_utility_services_1.OperationException(`No material view found with id ${args.source_id}`);
143
+ if (args.table_name && args.table_name !== row.table_name) {
144
+ throw new nestjs_utility_services_1.OperationException(`table_name '${args.table_name}' does not match source_id ${args.source_id}`);
145
+ }
146
+ return row;
147
+ }
148
+ if (args.table_name)
149
+ return this.requireRegisteredView(args.table_name);
150
+ throw new nestjs_utility_services_1.OperationException('table_name or source_id is required');
151
+ }
152
+ async upsertLiveColumn(row, liveCol, typeMap, sourceType) {
153
+ const column = await nestjs_utility_services_1.ColumnEntity.firstOrNew({
154
+ source_type: sourceType,
155
+ source_id: row.id,
156
+ name: liveCol.column_name,
157
+ });
158
+ const isNew = !column.id;
159
+ column.ordinal_position = Number(liveCol.ordinal_position);
160
+ const isNullable = liveCol.is_nullable === 'YES';
161
+ column.nullable = isNullable;
162
+ column.required = !isNullable;
163
+ column.type_id = this.resolveTypeId(liveCol.col_type || liveCol.udt_name || liveCol.data_type, typeMap);
164
+ if (isNew) {
165
+ const tenancy = this.tenancyColumn(row);
166
+ column.display_name = this.displayName(liveCol.column_name);
167
+ column.description = '';
168
+ column.visibility = liveCol.column_name !== tenancy;
169
+ column.query_params = '{}';
170
+ column.is_custom_column = false;
171
+ column.attributes = {};
172
+ }
173
+ await column.save();
174
+ return isNew;
175
+ }
176
+ async describeColumns(tableName, patches = []) {
177
+ const row = await this.requireRegisteredView(tableName);
178
+ if (!Array.isArray(patches) || !patches.length) {
179
+ throw new nestjs_utility_services_1.OperationException('columns array is required');
180
+ }
181
+ const missing = [];
182
+ const updated = [];
183
+ for (const patch of patches) {
184
+ if (!patch?.name)
185
+ throw new nestjs_utility_services_1.OperationException('each column patch requires name');
186
+ const column = await nestjs_utility_services_1.ColumnEntity.findOne({
187
+ where: { source_type: SourceHash.materialView, source_id: row.id, name: patch.name },
188
+ });
189
+ if (!column) {
190
+ missing.push(patch.name);
191
+ continue;
192
+ }
193
+ if (patch.display_name !== undefined)
194
+ column.display_name = patch.display_name;
195
+ if (patch.description !== undefined)
196
+ column.description = patch.description;
197
+ if (patch.visibility !== undefined)
198
+ column.visibility = Boolean(patch.visibility);
199
+ if (patch.attributes !== undefined) {
200
+ const parsed = this.parseColumnAttributes(patch.attributes, true);
201
+ column.attributes = { ...(column.attributes || {}), ...parsed };
202
+ }
203
+ await column.save();
204
+ updated.push(patch.name);
205
+ }
206
+ const gate = await this.evaluate(row, { persistDrop: true });
207
+ return { table_name: row.table_name, updated, missing, gate };
208
+ }
209
+ async validate(tableName) {
210
+ if (tableName) {
211
+ const row = await this.requireRegisteredView(tableName);
212
+ return this.evaluate(row, { persistDrop: true });
213
+ }
214
+ const rows = await nestjs_utility_services_1.MaterialViewEntity.find();
215
+ const views = [];
216
+ for (const row of rows) {
217
+ views.push(await this.evaluate(row, { persistDrop: true }));
218
+ }
219
+ return { views };
220
+ }
221
+ async evaluate(row, options) {
222
+ const findings = [];
223
+ const attributes = row.attributes || {};
224
+ const viewParse = this.tryParseViewAttributes(attributes);
225
+ if (viewParse.error)
226
+ findings.push(`view attributes: ${viewParse.error}`);
227
+ const parsed = viewParse.dto || new material_view_catalog_attributes_dto_1.MaterialViewCatalogAttributesDto();
228
+ const tenancy = parsed.tenancy_column || DEFAULT_TENANCY;
229
+ const catalogName = parsed.catalog_name || this.defaultCatalogName(row.table_name);
230
+ if (catalogName && !/^[a-z][a-z0-9_]{1,40}$/.test(catalogName)) {
231
+ findings.push(`catalog_name '${catalogName}' is invalid`);
232
+ }
233
+ if (row.table_name) {
234
+ const exists = await this.relationExists(row.table_name);
235
+ if (!exists)
236
+ findings.push(`relation '${row.table_name}' does not exist`);
237
+ }
238
+ else {
239
+ findings.push('table_name is missing');
240
+ }
241
+ const liveNames = new Set((await this.loadLiveColumnsSafe(row.table_name)).map((column) => column.column_name));
242
+ if (row.table_name && liveNames.size && !liveNames.has(tenancy)) {
243
+ findings.push(`tenancy column '${tenancy}' is missing from ${row.table_name}`);
244
+ }
245
+ const columns = row.id ? await nestjs_utility_services_1.ColumnEntity.find({ where: { source_type: SourceHash.materialView, source_id: row.id } }) : [];
246
+ if (row.id && columns.length === 0) {
247
+ findings.push('no_columns_registered');
248
+ }
249
+ const tenancyColumn = columns.find((column) => column.name === tenancy);
250
+ if (tenancyColumn?.visibility) {
251
+ findings.push(`tenancy column '${tenancy}' must not be agent-exposed (visibility=false)`);
252
+ }
253
+ const agentVisible = Boolean(parsed.agent_visible);
254
+ if (agentVisible && !(parsed.description || '').trim()) {
255
+ findings.push('agent_visible views require a non-empty description');
256
+ }
257
+ for (const column of columns) {
258
+ if (liveNames.size && !liveNames.has(column.name)) {
259
+ findings.push(`registered column '${column.name}' is missing from ${row.table_name}`);
260
+ }
261
+ const colParse = this.tryParseColumnAttributes(column.attributes || {});
262
+ if (colParse.error)
263
+ findings.push(`column '${column.name}' attributes: ${colParse.error}`);
264
+ const colAttrs = colParse.dto || new column_catalog_attributes_dto_1.ColumnCatalogAttributesDto();
265
+ if (agentVisible && !(column.description || '').trim()) {
266
+ findings.push(`column '${column.name}' needs a description`);
267
+ }
268
+ if (colAttrs.semantic_type === 'enum' && !this.hasEnumMap(colAttrs.enum_map)) {
269
+ findings.push(`column '${column.name}' is enum but has no enum_map`);
270
+ }
271
+ }
272
+ const ok = findings.length === 0;
273
+ let dropped = false;
274
+ if (!ok && agentVisible && options.persistDrop && row.id) {
275
+ row.attributes = { ...attributes, agent_visible: false };
276
+ await row.save();
277
+ dropped = true;
278
+ this.logger.warn(`reporting catalog gate: dropped agent_visible on ${row.table_name}: ${findings.join('; ')}`);
279
+ }
280
+ return {
281
+ table_name: row.table_name,
282
+ ok,
283
+ findings,
284
+ agent_visible: dropped ? false : agentVisible,
285
+ ...(dropped ? { dropped: true } : {}),
286
+ };
287
+ }
288
+ parseViewAttributes(raw, forbidUnknown) {
289
+ const parsed = this.tryParseViewAttributes(raw, forbidUnknown);
290
+ if (parsed.error)
291
+ throw new nestjs_utility_services_1.OperationException(`Invalid view attributes: ${parsed.error}`);
292
+ return parsed.dto;
293
+ }
294
+ parseColumnAttributes(raw, forbidUnknown) {
295
+ const parsed = this.tryParseColumnAttributes(raw, forbidUnknown);
296
+ if (parsed.error)
297
+ throw new nestjs_utility_services_1.OperationException(`Invalid column attributes: ${parsed.error}`);
298
+ return parsed.dto;
299
+ }
300
+ tryParseViewAttributes(raw, forbidUnknown = true) {
301
+ const dto = (0, class_transformer_1.plainToInstance)(material_view_catalog_attributes_dto_1.MaterialViewCatalogAttributesDto, raw || {}, { enableImplicitConversion: true });
302
+ const errors = (0, class_validator_1.validateSync)(dto, { whitelist: true, forbidNonWhitelisted: forbidUnknown });
303
+ return { dto, error: this.formatErrors(errors) };
304
+ }
305
+ tryParseColumnAttributes(raw, forbidUnknown = false) {
306
+ const dto = (0, class_transformer_1.plainToInstance)(column_catalog_attributes_dto_1.ColumnCatalogAttributesDto, raw || {}, { enableImplicitConversion: true });
307
+ const errors = (0, class_validator_1.validateSync)(dto, { whitelist: true, forbidNonWhitelisted: forbidUnknown });
308
+ return { dto, error: this.formatErrors(errors) };
309
+ }
310
+ formatErrors(errors) {
311
+ if (!errors.length)
312
+ return null;
313
+ return errors
314
+ .map((error) => {
315
+ const constraints = error.constraints ? Object.values(error.constraints).join(', ') : 'invalid';
316
+ return `${error.property}: ${constraints}`;
317
+ })
318
+ .join('; ');
319
+ }
320
+ applyViewDefaults(tableName, attributes) {
321
+ if (!attributes.catalog_name)
322
+ attributes.catalog_name = this.defaultCatalogName(tableName);
323
+ if (!attributes.tenancy_column)
324
+ attributes.tenancy_column = DEFAULT_TENANCY;
325
+ if (attributes.row_cap === undefined)
326
+ attributes.row_cap = 500;
327
+ if (attributes.agent_visible === undefined)
328
+ attributes.agent_visible = false;
329
+ }
330
+ defaultCatalogName(tableName) {
331
+ return tableName.replace(/^rpt_/, '') || tableName;
332
+ }
333
+ tenancyColumn(row) {
334
+ return row.attributes?.tenancy_column || DEFAULT_TENANCY;
335
+ }
336
+ asViewRow(partial) {
337
+ const row = new nestjs_utility_services_1.MaterialViewEntity();
338
+ row.table_name = partial.table_name;
339
+ row.attributes = partial.attributes;
340
+ return row;
341
+ }
342
+ async requireRegisteredView(tableName) {
343
+ const name = this.assertTableName(tableName);
344
+ const row = await nestjs_utility_services_1.MaterialViewEntity.findOne({ where: { table_name: name } });
345
+ if (!row)
346
+ throw new nestjs_utility_services_1.OperationException(`table_name '${name}' is not a registered material view`);
347
+ return row;
348
+ }
349
+ assertTableName(tableName) {
350
+ if (!tableName || !material_view_catalog_attributes_dto_1.TABLE_NAME_PATTERN.test(tableName)) {
351
+ throw new nestjs_utility_services_1.OperationException('table_name must match ^[a-z][a-z0-9_]{1,62}$');
352
+ }
353
+ return tableName;
354
+ }
355
+ quoteIdent(tableName) {
356
+ return `"${tableName.replace(/"/g, '""')}"`;
357
+ }
358
+ clampLimit(limit) {
359
+ const n = Number(limit);
360
+ if (!Number.isFinite(n) || n <= 0)
361
+ return DEFAULT_SAMPLE_LIMIT;
362
+ return Math.min(Math.floor(n), SAMPLE_CAP);
363
+ }
364
+ clampOffset(offset) {
365
+ const n = Number(offset);
366
+ if (!Number.isFinite(n) || n <= 0)
367
+ return 0;
368
+ return Math.floor(n);
369
+ }
370
+ async assertRelationExists(tableName) {
371
+ if (!(await this.relationExists(tableName))) {
372
+ throw new nestjs_utility_services_1.OperationException(`materialized view '${tableName}' does not exist`);
373
+ }
374
+ }
375
+ async relationExists(tableName) {
376
+ if (!tableName || !material_view_catalog_attributes_dto_1.TABLE_NAME_PATTERN.test(tableName))
377
+ return false;
378
+ const row = await this.boundReadFirst(`SELECT 1 AS ok
379
+ FROM pg_catalog.pg_class c
380
+ JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
381
+ WHERE n.nspname = 'public' AND c.relname = $1 AND c.relkind = 'm'
382
+ LIMIT 1`, [tableName], 'ok');
383
+ return Boolean(row);
384
+ }
385
+ async boundReadFirst(query, params = [], column) {
386
+ const rows = await this.sqlService.boundRead(query, params);
387
+ const data = Array.isArray(rows) ? rows[0] : null;
388
+ if (!column)
389
+ return data;
390
+ return data?.[column];
391
+ }
392
+ async loadLiveColumns(tableName) {
393
+ const rows = await this.sqlService.boundRead(`SELECT a.attname,
394
+ format_type(a.atttypid, a.atttypmod) AS col_type,
395
+ a.attnum,
396
+ CASE WHEN a.attnotnull THEN 'NO' ELSE 'YES' END AS is_nullable
397
+ FROM pg_catalog.pg_attribute a
398
+ JOIN pg_catalog.pg_class c ON c.oid = a.attrelid
399
+ JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
400
+ WHERE n.nspname = 'public' AND c.relname = $1 AND c.relkind = 'm'
401
+ AND a.attnum > 0 AND NOT a.attisdropped
402
+ ORDER BY a.attnum`, [tableName]);
403
+ if (!Array.isArray(rows))
404
+ return [];
405
+ return rows.map((row) => this.normalizeLiveColumn(row));
406
+ }
407
+ normalizeLiveColumn(row) {
408
+ const columnName = String(row.attname ?? row.column_name ?? '');
409
+ const colType = String(row.col_type ?? row.udt_name ?? row.data_type ?? '');
410
+ return {
411
+ column_name: columnName,
412
+ col_type: colType,
413
+ ordinal_position: Number(row.attnum ?? row.ordinal_position ?? 0),
414
+ is_nullable: String(row.is_nullable ?? 'YES'),
415
+ };
416
+ }
417
+ resolveTypeId(colType, typeMap) {
418
+ const raw = String(colType || '')
419
+ .toLowerCase()
420
+ .trim();
421
+ const base = raw.replace(/\(.*/, '').trim();
422
+ return typeMap[raw] || typeMap[base] || 1;
423
+ }
424
+ async loadLiveColumnsSafe(tableName) {
425
+ if (!tableName || !material_view_catalog_attributes_dto_1.TABLE_NAME_PATTERN.test(tableName))
426
+ return [];
427
+ try {
428
+ return await this.loadLiveColumns(tableName);
429
+ }
430
+ catch {
431
+ return [];
432
+ }
433
+ }
434
+ async columnTypeMapping() {
435
+ const mapping = {};
436
+ const types = await nestjs_utility_services_1.ColumnDefinitionEntity.find({ where: { supported_identifiers: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()) } });
437
+ for (const type of types) {
438
+ for (const identifier of String(type.supported_identifiers || '').split(',')) {
439
+ const key = identifier.trim().toLowerCase();
440
+ if (key)
441
+ mapping[key] = type.id;
442
+ }
443
+ }
444
+ return mapping;
445
+ }
446
+ displayName(name) {
447
+ const stripped = name.endsWith('_id') ? name.slice(0, -3) : name;
448
+ return stripped.replace(/_/g, ' ').replace(/\b[a-z]/g, (char) => char.toUpperCase());
449
+ }
450
+ hasEnumMap(map) {
451
+ return Boolean(map && typeof map === 'object' && Object.keys(map).length);
452
+ }
453
+ };
454
+ exports.AdminReportViewService = AdminReportViewService;
455
+ exports.AdminReportViewService = AdminReportViewService = AdminReportViewService_1 = __decorate([
456
+ (0, common_1.Injectable)(),
457
+ __metadata("design:paramtypes", [nestjs_utility_services_1.SqlService])
458
+ ], AdminReportViewService);
459
+ //# sourceMappingURL=admin.report.view.service.js.map