@ffschrattenecker/tm1-mcp-server 6.0.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/CHANGELOG.md +1211 -0
- package/LICENSE +21 -0
- package/NOTICE +34 -0
- package/README.md +276 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.js +238 -0
- package/dist/http-transport.d.ts +8 -0
- package/dist/http-transport.js +132 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +164 -0
- package/dist/lib/callgraph/callGraph.d.ts +124 -0
- package/dist/lib/callgraph/callGraph.js +334 -0
- package/dist/lib/callgraph/choreGraph.d.ts +23 -0
- package/dist/lib/callgraph/choreGraph.js +102 -0
- package/dist/lib/callgraph/dataFlow.d.ts +74 -0
- package/dist/lib/callgraph/dataFlow.js +271 -0
- package/dist/lib/callgraph/datasourceMembership.d.ts +31 -0
- package/dist/lib/callgraph/datasourceMembership.js +142 -0
- package/dist/lib/callgraph/lintTypes.d.ts +28 -0
- package/dist/lib/callgraph/lintTypes.js +2 -0
- package/dist/lib/callgraph/mdxMembers.d.ts +29 -0
- package/dist/lib/callgraph/mdxMembers.js +97 -0
- package/dist/lib/callgraph/referenceIndex.d.ts +179 -0
- package/dist/lib/callgraph/referenceIndex.js +584 -0
- package/dist/lib/callgraph/rulesLinter.d.ts +55 -0
- package/dist/lib/callgraph/rulesLinter.js +776 -0
- package/dist/lib/callgraph/rulesParser.d.ts +26 -0
- package/dist/lib/callgraph/rulesParser.js +71 -0
- package/dist/lib/callgraph/subsetUsage.d.ts +16 -0
- package/dist/lib/callgraph/subsetUsage.js +134 -0
- package/dist/lib/callgraph/tiParser.d.ts +21 -0
- package/dist/lib/callgraph/tiParser.js +672 -0
- package/dist/lib/callgraph/tiSignatures.d.ts +32 -0
- package/dist/lib/callgraph/tiSignatures.js +6185 -0
- package/dist/lib/callgraph/tm1-adapter.d.ts +32 -0
- package/dist/lib/callgraph/tm1-adapter.js +159 -0
- package/dist/lib/callgraph/types.d.ts +53 -0
- package/dist/lib/callgraph/types.js +2 -0
- package/dist/lib/callgraph/variableEnv.d.ts +86 -0
- package/dist/lib/callgraph/variableEnv.js +214 -0
- package/dist/lib/cell-address.d.ts +12 -0
- package/dist/lib/cell-address.js +71 -0
- package/dist/lib/complexity/antipatterns.d.ts +22 -0
- package/dist/lib/complexity/antipatterns.js +302 -0
- package/dist/lib/complexity/comment-classifier.d.ts +24 -0
- package/dist/lib/complexity/comment-classifier.js +43 -0
- package/dist/lib/complexity/cross-process.d.ts +78 -0
- package/dist/lib/complexity/cross-process.js +114 -0
- package/dist/lib/complexity/process-metrics.d.ts +78 -0
- package/dist/lib/complexity/process-metrics.js +278 -0
- package/dist/lib/complexity/rules-metrics.d.ts +31 -0
- package/dist/lib/complexity/rules-metrics.js +99 -0
- package/dist/lib/concurrency.d.ts +11 -0
- package/dist/lib/concurrency.js +27 -0
- package/dist/lib/control-name.d.ts +10 -0
- package/dist/lib/control-name.js +10 -0
- package/dist/lib/coordinate-error.d.ts +3 -0
- package/dist/lib/coordinate-error.js +29 -0
- package/dist/lib/credential-format.d.ts +23 -0
- package/dist/lib/credential-format.js +25 -0
- package/dist/lib/cube-stats/fetcher.d.ts +106 -0
- package/dist/lib/cube-stats/fetcher.js +194 -0
- package/dist/lib/feeders/brackets.d.ts +47 -0
- package/dist/lib/feeders/brackets.js +195 -0
- package/dist/lib/feeders/element-type-cache.d.ts +42 -0
- package/dist/lib/feeders/element-type-cache.js +86 -0
- package/dist/lib/feeders/static-heuristics.d.ts +101 -0
- package/dist/lib/feeders/static-heuristics.js +202 -0
- package/dist/lib/git-process.d.ts +67 -0
- package/dist/lib/git-process.js +243 -0
- package/dist/lib/mask-secrets.d.ts +10 -0
- package/dist/lib/mask-secrets.js +99 -0
- package/dist/lib/mdx.d.ts +3 -0
- package/dist/lib/mdx.js +13 -0
- package/dist/lib/naming/odata-filter.d.ts +15 -0
- package/dist/lib/naming/odata-filter.js +81 -0
- package/dist/lib/naming/rules.d.ts +34 -0
- package/dist/lib/naming/rules.js +215 -0
- package/dist/lib/pro-parser.d.ts +19 -0
- package/dist/lib/pro-parser.js +260 -0
- package/dist/lib/pro-serializer.d.ts +19 -0
- package/dist/lib/pro-serializer.js +170 -0
- package/dist/lib/process-parts-schema.d.ts +45 -0
- package/dist/lib/process-parts-schema.js +46 -0
- package/dist/lib/process-refs.d.ts +88 -0
- package/dist/lib/process-refs.js +441 -0
- package/dist/lib/rules-outline.d.ts +29 -0
- package/dist/lib/rules-outline.js +68 -0
- package/dist/lib/rules-patch.d.ts +6 -0
- package/dist/lib/rules-patch.js +59 -0
- package/dist/lib/safe-regex.d.ts +15 -0
- package/dist/lib/safe-regex.js +37 -0
- package/dist/lib/sample-cells.d.ts +48 -0
- package/dist/lib/sample-cells.js +146 -0
- package/dist/lib/slim-json-schema.d.ts +20 -0
- package/dist/lib/slim-json-schema.js +68 -0
- package/dist/lib/strip-comments.d.ts +23 -0
- package/dist/lib/strip-comments.js +61 -0
- package/dist/lib/tm1-events.d.ts +16 -0
- package/dist/lib/tm1-events.js +29 -0
- package/dist/lib/v12-compat/deprecated-ti.d.ts +17 -0
- package/dist/lib/v12-compat/deprecated-ti.js +257 -0
- package/dist/lib/v12-compat/scanner.d.ts +10 -0
- package/dist/lib/v12-compat/scanner.js +43 -0
- package/dist/lib/variables-ui-data.d.ts +26 -0
- package/dist/lib/variables-ui-data.js +77 -0
- package/dist/load-env.d.ts +2 -0
- package/dist/load-env.js +29 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.js +60 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.js +141 -0
- package/dist/resources/index.d.ts +5 -0
- package/dist/resources/index.js +237 -0
- package/dist/resources/list-handler.d.ts +40 -0
- package/dist/resources/list-handler.js +86 -0
- package/dist/resources/subscriptions.d.ts +19 -0
- package/dist/resources/subscriptions.js +80 -0
- package/dist/schemas/cells.d.ts +17 -0
- package/dist/schemas/cells.js +13 -0
- package/dist/schemas/common.d.ts +16 -0
- package/dist/schemas/common.js +14 -0
- package/dist/schemas/index.d.ts +10 -0
- package/dist/schemas/index.js +23 -0
- package/dist/schemas/metadata.d.ts +70 -0
- package/dist/schemas/metadata.js +47 -0
- package/dist/schemas/monitoring.d.ts +95 -0
- package/dist/schemas/monitoring.js +69 -0
- package/dist/schemas/processes.d.ts +74 -0
- package/dist/schemas/processes.js +66 -0
- package/dist/schemas/scheduling.d.ts +13 -0
- package/dist/schemas/scheduling.js +13 -0
- package/dist/schemas/security.d.ts +19 -0
- package/dist/schemas/security.js +16 -0
- package/dist/schemas/subsets.d.ts +12 -0
- package/dist/schemas/subsets.js +12 -0
- package/dist/schemas/views.d.ts +9 -0
- package/dist/schemas/views.js +9 -0
- package/dist/session-manager.d.ts +79 -0
- package/dist/session-manager.js +281 -0
- package/dist/tm1-client/connection/profile.d.ts +13 -0
- package/dist/tm1-client/connection/profile.js +99 -0
- package/dist/tm1-client/dispatcher.d.ts +5 -0
- package/dist/tm1-client/dispatcher.js +31 -0
- package/dist/tm1-client/http.d.ts +81 -0
- package/dist/tm1-client/http.js +547 -0
- package/dist/tm1-client/services/batch-service.d.ts +123 -0
- package/dist/tm1-client/services/batch-service.js +455 -0
- package/dist/tm1-client/services/cell-service.d.ts +71 -0
- package/dist/tm1-client/services/cell-service.js +333 -0
- package/dist/tm1-client/services/cellset-transform.d.ts +26 -0
- package/dist/tm1-client/services/cellset-transform.js +80 -0
- package/dist/tm1-client/services/chore-service.d.ts +68 -0
- package/dist/tm1-client/services/chore-service.js +179 -0
- package/dist/tm1-client/services/chore-status.d.ts +11 -0
- package/dist/tm1-client/services/chore-status.js +127 -0
- package/dist/tm1-client/services/cube-service.d.ts +134 -0
- package/dist/tm1-client/services/cube-service.js +294 -0
- package/dist/tm1-client/services/dimension-service.d.ts +118 -0
- package/dist/tm1-client/services/dimension-service.js +249 -0
- package/dist/tm1-client/services/element-service.d.ts +245 -0
- package/dist/tm1-client/services/element-service.js +809 -0
- package/dist/tm1-client/services/fallback.d.ts +44 -0
- package/dist/tm1-client/services/fallback.js +72 -0
- package/dist/tm1-client/services/file-service.d.ts +53 -0
- package/dist/tm1-client/services/file-service.js +218 -0
- package/dist/tm1-client/services/hierarchy-service.d.ts +129 -0
- package/dist/tm1-client/services/hierarchy-service.js +332 -0
- package/dist/tm1-client/services/monitoring-service.d.ts +34 -0
- package/dist/tm1-client/services/monitoring-service.js +123 -0
- package/dist/tm1-client/services/odata-page.d.ts +71 -0
- package/dist/tm1-client/services/odata-page.js +87 -0
- package/dist/tm1-client/services/process-service.d.ts +278 -0
- package/dist/tm1-client/services/process-service.js +874 -0
- package/dist/tm1-client/services/process-status.d.ts +21 -0
- package/dist/tm1-client/services/process-status.js +89 -0
- package/dist/tm1-client/services/security-service.d.ts +50 -0
- package/dist/tm1-client/services/security-service.js +93 -0
- package/dist/tm1-client/services/server-service.d.ts +116 -0
- package/dist/tm1-client/services/server-service.js +504 -0
- package/dist/tm1-client/services/subset-service.d.ts +37 -0
- package/dist/tm1-client/services/subset-service.js +122 -0
- package/dist/tm1-client/services/view-service.d.ts +46 -0
- package/dist/tm1-client/services/view-service.js +287 -0
- package/dist/tm1-client.d.ts +56 -0
- package/dist/tm1-client.js +126 -0
- package/dist/tools/analysis/analyze-callgraph.d.ts +28 -0
- package/dist/tools/analysis/analyze-callgraph.js +350 -0
- package/dist/tools/analysis/analyze-chore-graph.d.ts +2 -0
- package/dist/tools/analysis/analyze-chore-graph.js +148 -0
- package/dist/tools/analysis/analyze-object-usage.d.ts +2 -0
- package/dist/tools/analysis/analyze-object-usage.js +143 -0
- package/dist/tools/analysis/audit-complexity.d.ts +2 -0
- package/dist/tools/analysis/audit-complexity.js +255 -0
- package/dist/tools/analysis/audit-feeders.d.ts +2 -0
- package/dist/tools/analysis/audit-feeders.js +417 -0
- package/dist/tools/analysis/audit-naming.d.ts +2 -0
- package/dist/tools/analysis/audit-naming.js +379 -0
- package/dist/tools/analysis/check-v12-readiness.d.ts +2 -0
- package/dist/tools/analysis/check-v12-readiness.js +136 -0
- package/dist/tools/analysis/find-orphan-dimensions.d.ts +2 -0
- package/dist/tools/analysis/find-orphan-dimensions.js +55 -0
- package/dist/tools/analysis/invalidate-callgraph-cache.d.ts +2 -0
- package/dist/tools/analysis/invalidate-callgraph-cache.js +40 -0
- package/dist/tools/analysis/trace-data-flow.d.ts +2 -0
- package/dist/tools/analysis/trace-data-flow.js +138 -0
- package/dist/tools/annotations.d.ts +12 -0
- package/dist/tools/annotations.js +61 -0
- package/dist/tools/celldata/check-feeders.d.ts +2 -0
- package/dist/tools/celldata/check-feeders.js +48 -0
- package/dist/tools/celldata/check-writable-coords.d.ts +2 -0
- package/dist/tools/celldata/check-writable-coords.js +126 -0
- package/dist/tools/celldata/execute-mdx.d.ts +17 -0
- package/dist/tools/celldata/execute-mdx.js +126 -0
- package/dist/tools/celldata/get-cell-value.d.ts +2 -0
- package/dist/tools/celldata/get-cell-value.js +30 -0
- package/dist/tools/celldata/get-view-definition.d.ts +2 -0
- package/dist/tools/celldata/get-view-definition.js +29 -0
- package/dist/tools/celldata/get-view.d.ts +2 -0
- package/dist/tools/celldata/get-view.js +55 -0
- package/dist/tools/celldata/sample-cells.d.ts +2 -0
- package/dist/tools/celldata/sample-cells.js +101 -0
- package/dist/tools/celldata/trace-cell-calculation.d.ts +2 -0
- package/dist/tools/celldata/trace-cell-calculation.js +53 -0
- package/dist/tools/celldata/trace-feeders.d.ts +2 -0
- package/dist/tools/celldata/trace-feeders.js +44 -0
- package/dist/tools/celldata/write-cells.d.ts +2 -0
- package/dist/tools/celldata/write-cells.js +65 -0
- package/dist/tools/confirm.d.ts +10 -0
- package/dist/tools/confirm.js +64 -0
- package/dist/tools/define-tool.d.ts +51 -0
- package/dist/tools/define-tool.js +49 -0
- package/dist/tools/dimension-management/bulk-upsert-elements.d.ts +2 -0
- package/dist/tools/dimension-management/bulk-upsert-elements.js +103 -0
- package/dist/tools/dimension-management/create-dimension.d.ts +2 -0
- package/dist/tools/dimension-management/create-dimension.js +22 -0
- package/dist/tools/dimension-management/create-element-attribute.d.ts +2 -0
- package/dist/tools/dimension-management/create-element-attribute.js +26 -0
- package/dist/tools/dimension-management/create-element.d.ts +2 -0
- package/dist/tools/dimension-management/create-element.js +31 -0
- package/dist/tools/dimension-management/create-hierarchy.d.ts +2 -0
- package/dist/tools/dimension-management/create-hierarchy.js +22 -0
- package/dist/tools/dimension-management/delete-dimension.d.ts +2 -0
- package/dist/tools/dimension-management/delete-dimension.js +25 -0
- package/dist/tools/dimension-management/delete-element.d.ts +2 -0
- package/dist/tools/dimension-management/delete-element.js +26 -0
- package/dist/tools/dimension-management/delete-elements.d.ts +2 -0
- package/dist/tools/dimension-management/delete-elements.js +44 -0
- package/dist/tools/dimension-management/delete-hierarchy.d.ts +2 -0
- package/dist/tools/dimension-management/delete-hierarchy.js +35 -0
- package/dist/tools/dimension-management/get-element-attribute-values.d.ts +2 -0
- package/dist/tools/dimension-management/get-element-attribute-values.js +77 -0
- package/dist/tools/dimension-management/list-element-attributes.d.ts +2 -0
- package/dist/tools/dimension-management/list-element-attributes.js +31 -0
- package/dist/tools/dimension-management/move-element.d.ts +2 -0
- package/dist/tools/dimension-management/move-element.js +28 -0
- package/dist/tools/dimension-management/update-element-attribute-value.d.ts +2 -0
- package/dist/tools/dimension-management/update-element-attribute-value.js +80 -0
- package/dist/tools/dimension-management/update-element.d.ts +2 -0
- package/dist/tools/dimension-management/update-element.js +35 -0
- package/dist/tools/error-format.d.ts +22 -0
- package/dist/tools/error-format.js +130 -0
- package/dist/tools/fileops/delete-file.d.ts +2 -0
- package/dist/tools/fileops/delete-file.js +32 -0
- package/dist/tools/fileops/get-file-content.d.ts +2 -0
- package/dist/tools/fileops/get-file-content.js +76 -0
- package/dist/tools/fileops/list-files.d.ts +2 -0
- package/dist/tools/fileops/list-files.js +43 -0
- package/dist/tools/fileops/search-files.d.ts +2 -0
- package/dist/tools/fileops/search-files.js +76 -0
- package/dist/tools/fileops/upload-file.d.ts +2 -0
- package/dist/tools/fileops/upload-file.js +69 -0
- package/dist/tools/format.d.ts +57 -0
- package/dist/tools/format.js +157 -0
- package/dist/tools/hierarchy.d.ts +6 -0
- package/dist/tools/hierarchy.js +27 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +263 -0
- package/dist/tools/local-file.d.ts +16 -0
- package/dist/tools/local-file.js +88 -0
- package/dist/tools/metadata/get-ancestors.d.ts +2 -0
- package/dist/tools/metadata/get-ancestors.js +36 -0
- package/dist/tools/metadata/get-descendants.d.ts +2 -0
- package/dist/tools/metadata/get-descendants.js +64 -0
- package/dist/tools/metadata/get-hierarchy.d.ts +2 -0
- package/dist/tools/metadata/get-hierarchy.js +130 -0
- package/dist/tools/metadata/list-chores.d.ts +2 -0
- package/dist/tools/metadata/list-chores.js +62 -0
- package/dist/tools/metadata/list-cubes.d.ts +2 -0
- package/dist/tools/metadata/list-cubes.js +128 -0
- package/dist/tools/metadata/list-dimensions.d.ts +2 -0
- package/dist/tools/metadata/list-dimensions.js +131 -0
- package/dist/tools/metadata/list-processes-grouped.d.ts +2 -0
- package/dist/tools/metadata/list-processes-grouped.js +96 -0
- package/dist/tools/metadata/list-processes.d.ts +2 -0
- package/dist/tools/metadata/list-processes.js +108 -0
- package/dist/tools/metadata/resolve-default-members.d.ts +2 -0
- package/dist/tools/metadata/resolve-default-members.js +46 -0
- package/dist/tools/model-building/check-cube-rule.d.ts +2 -0
- package/dist/tools/model-building/check-cube-rule.js +51 -0
- package/dist/tools/model-building/clear-cube.d.ts +2 -0
- package/dist/tools/model-building/clear-cube.js +46 -0
- package/dist/tools/model-building/create-cube.d.ts +2 -0
- package/dist/tools/model-building/create-cube.js +34 -0
- package/dist/tools/model-building/delete-cube.d.ts +2 -0
- package/dist/tools/model-building/delete-cube.js +27 -0
- package/dist/tools/model-building/get-all-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/get-all-cube-rules.js +149 -0
- package/dist/tools/model-building/get-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/get-cube-rules.js +69 -0
- package/dist/tools/model-building/rules-source.d.ts +21 -0
- package/dist/tools/model-building/rules-source.js +49 -0
- package/dist/tools/model-building/search-rules.d.ts +2 -0
- package/dist/tools/model-building/search-rules.js +132 -0
- package/dist/tools/model-building/set-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/set-cube-rules.js +81 -0
- package/dist/tools/model-building/unload-cube.d.ts +2 -0
- package/dist/tools/model-building/unload-cube.js +23 -0
- package/dist/tools/operations/diagnose-process-error.d.ts +2 -0
- package/dist/tools/operations/diagnose-process-error.js +178 -0
- package/dist/tools/operations/error-log-helpers.d.ts +25 -0
- package/dist/tools/operations/error-log-helpers.js +57 -0
- package/dist/tools/operations/get-audit-log.d.ts +2 -0
- package/dist/tools/operations/get-audit-log.js +70 -0
- package/dist/tools/operations/get-cube-stats.d.ts +2 -0
- package/dist/tools/operations/get-cube-stats.js +107 -0
- package/dist/tools/operations/get-error-log-content.d.ts +2 -0
- package/dist/tools/operations/get-error-log-content.js +164 -0
- package/dist/tools/operations/get-jobs.d.ts +3 -0
- package/dist/tools/operations/get-jobs.js +51 -0
- package/dist/tools/operations/get-message-log.d.ts +2 -0
- package/dist/tools/operations/get-message-log.js +63 -0
- package/dist/tools/operations/get-server-info.d.ts +2 -0
- package/dist/tools/operations/get-server-info.js +180 -0
- package/dist/tools/operations/get-server-state.d.ts +2 -0
- package/dist/tools/operations/get-server-state.js +129 -0
- package/dist/tools/operations/get-sessions.d.ts +2 -0
- package/dist/tools/operations/get-sessions.js +76 -0
- package/dist/tools/operations/get-threads.d.ts +3 -0
- package/dist/tools/operations/get-threads.js +50 -0
- package/dist/tools/operations/get-transaction-log.d.ts +2 -0
- package/dist/tools/operations/get-transaction-log.js +63 -0
- package/dist/tools/operations/list-error-logs.d.ts +8 -0
- package/dist/tools/operations/list-error-logs.js +157 -0
- package/dist/tools/operations/save-data.d.ts +2 -0
- package/dist/tools/operations/save-data.js +50 -0
- package/dist/tools/pagination.d.ts +32 -0
- package/dist/tools/pagination.js +116 -0
- package/dist/tools/scheduling/create-chore.d.ts +2 -0
- package/dist/tools/scheduling/create-chore.js +93 -0
- package/dist/tools/scheduling/delete-chore.d.ts +2 -0
- package/dist/tools/scheduling/delete-chore.js +22 -0
- package/dist/tools/scheduling/execute-chore.d.ts +2 -0
- package/dist/tools/scheduling/execute-chore.js +52 -0
- package/dist/tools/scheduling/toggle-chore.d.ts +2 -0
- package/dist/tools/scheduling/toggle-chore.js +22 -0
- package/dist/tools/scheduling/update-chore.d.ts +2 -0
- package/dist/tools/scheduling/update-chore.js +71 -0
- package/dist/tools/schemas/common.d.ts +10 -0
- package/dist/tools/schemas/common.js +23 -0
- package/dist/tools/schemas/items-analysis.d.ts +394 -0
- package/dist/tools/schemas/items-analysis.js +419 -0
- package/dist/tools/schemas/items-cells.d.ts +70 -0
- package/dist/tools/schemas/items-cells.js +65 -0
- package/dist/tools/schemas/items-common.d.ts +18 -0
- package/dist/tools/schemas/items-common.js +39 -0
- package/dist/tools/schemas/items-fileops.d.ts +11 -0
- package/dist/tools/schemas/items-fileops.js +13 -0
- package/dist/tools/schemas/items-metadata.d.ts +262 -0
- package/dist/tools/schemas/items-metadata.js +184 -0
- package/dist/tools/schemas/items-monitoring.d.ts +79 -0
- package/dist/tools/schemas/items-monitoring.js +78 -0
- package/dist/tools/schemas/items-processes.d.ts +279 -0
- package/dist/tools/schemas/items-processes.js +235 -0
- package/dist/tools/schemas/items-scheduling.d.ts +25 -0
- package/dist/tools/schemas/items-scheduling.js +26 -0
- package/dist/tools/schemas/items-security.d.ts +19 -0
- package/dist/tools/schemas/items-security.js +12 -0
- package/dist/tools/schemas/items-subsets.d.ts +2 -0
- package/dist/tools/schemas/items-subsets.js +4 -0
- package/dist/tools/schemas/items-views.d.ts +38 -0
- package/dist/tools/schemas/items-views.js +26 -0
- package/dist/tools/schemas/items.d.ts +12 -0
- package/dist/tools/schemas/items.js +23 -0
- package/dist/tools/schemas/markdown-capable.d.ts +21 -0
- package/dist/tools/schemas/markdown-capable.js +58 -0
- package/dist/tools/schemas/output-schema.d.ts +24 -0
- package/dist/tools/schemas/output-schema.js +25 -0
- package/dist/tools/security/assign-client-group.d.ts +2 -0
- package/dist/tools/security/assign-client-group.js +20 -0
- package/dist/tools/security/create-client.d.ts +2 -0
- package/dist/tools/security/create-client.js +28 -0
- package/dist/tools/security/delete-client.d.ts +2 -0
- package/dist/tools/security/delete-client.js +22 -0
- package/dist/tools/security/get-client.d.ts +2 -0
- package/dist/tools/security/get-client.js +20 -0
- package/dist/tools/security/list-clients.d.ts +2 -0
- package/dist/tools/security/list-clients.js +86 -0
- package/dist/tools/security/list-groups.d.ts +2 -0
- package/dist/tools/security/list-groups.js +43 -0
- package/dist/tools/security/remove-client-group.d.ts +2 -0
- package/dist/tools/security/remove-client-group.js +27 -0
- package/dist/tools/security/update-client.d.ts +2 -0
- package/dist/tools/security/update-client.js +22 -0
- package/dist/tools/subsets/create-subset.d.ts +2 -0
- package/dist/tools/subsets/create-subset.js +44 -0
- package/dist/tools/subsets/delete-subset.d.ts +2 -0
- package/dist/tools/subsets/delete-subset.js +26 -0
- package/dist/tools/subsets/get-subset.d.ts +2 -0
- package/dist/tools/subsets/get-subset.js +29 -0
- package/dist/tools/subsets/list-subsets.d.ts +2 -0
- package/dist/tools/subsets/list-subsets.js +36 -0
- package/dist/tools/subsets/update-subset.d.ts +2 -0
- package/dist/tools/subsets/update-subset.js +33 -0
- package/dist/tools/ti-development/check-process-code.d.ts +2 -0
- package/dist/tools/ti-development/check-process-code.js +96 -0
- package/dist/tools/ti-development/compile-process.d.ts +2 -0
- package/dist/tools/ti-development/compile-process.js +32 -0
- package/dist/tools/ti-development/copy-process.d.ts +2 -0
- package/dist/tools/ti-development/copy-process.js +32 -0
- package/dist/tools/ti-development/delete-process.d.ts +2 -0
- package/dist/tools/ti-development/delete-process.js +26 -0
- package/dist/tools/ti-development/diff-process-with-file.d.ts +2 -0
- package/dist/tools/ti-development/diff-process-with-file.js +208 -0
- package/dist/tools/ti-development/diff-processes.d.ts +2 -0
- package/dist/tools/ti-development/diff-processes.js +312 -0
- package/dist/tools/ti-development/execute-process.d.ts +8 -0
- package/dist/tools/ti-development/execute-process.js +109 -0
- package/dist/tools/ti-development/export-process-to-git.d.ts +2 -0
- package/dist/tools/ti-development/export-process-to-git.js +113 -0
- package/dist/tools/ti-development/export-process-to-pro.d.ts +2 -0
- package/dist/tools/ti-development/export-process-to-pro.js +117 -0
- package/dist/tools/ti-development/get-all-processes-code.d.ts +2 -0
- package/dist/tools/ti-development/get-all-processes-code.js +131 -0
- package/dist/tools/ti-development/get-process-code.d.ts +2 -0
- package/dist/tools/ti-development/get-process-code.js +100 -0
- package/dist/tools/ti-development/get-process-datasource.d.ts +2 -0
- package/dist/tools/ti-development/get-process-datasource.js +20 -0
- package/dist/tools/ti-development/get-process-parameters.d.ts +2 -0
- package/dist/tools/ti-development/get-process-parameters.js +25 -0
- package/dist/tools/ti-development/get-process-variables.d.ts +2 -0
- package/dist/tools/ti-development/get-process-variables.js +38 -0
- package/dist/tools/ti-development/get-process.d.ts +2 -0
- package/dist/tools/ti-development/get-process.js +163 -0
- package/dist/tools/ti-development/import-pro-file.d.ts +2 -0
- package/dist/tools/ti-development/import-pro-file.js +153 -0
- package/dist/tools/ti-development/import-process-from-git.d.ts +2 -0
- package/dist/tools/ti-development/import-process-from-git.js +198 -0
- package/dist/tools/ti-development/install-pro-bundle.d.ts +2 -0
- package/dist/tools/ti-development/install-pro-bundle.js +288 -0
- package/dist/tools/ti-development/preflight.d.ts +39 -0
- package/dist/tools/ti-development/preflight.js +56 -0
- package/dist/tools/ti-development/process-backup.d.ts +29 -0
- package/dist/tools/ti-development/process-backup.js +118 -0
- package/dist/tools/ti-development/search-code.d.ts +2 -0
- package/dist/tools/ti-development/search-code.js +208 -0
- package/dist/tools/ti-development/upsert-process.d.ts +2 -0
- package/dist/tools/ti-development/upsert-process.js +167 -0
- package/dist/tools/ti-development/validate-process-refs.d.ts +2 -0
- package/dist/tools/ti-development/validate-process-refs.js +73 -0
- package/dist/tools/views/create-mdx-view.d.ts +2 -0
- package/dist/tools/views/create-mdx-view.js +21 -0
- package/dist/tools/views/create-native-view.d.ts +2 -0
- package/dist/tools/views/create-native-view.js +81 -0
- package/dist/tools/views/delete-view.d.ts +2 -0
- package/dist/tools/views/delete-view.js +23 -0
- package/dist/tools/views/list-views.d.ts +2 -0
- package/dist/tools/views/list-views.js +32 -0
- package/dist/tools/with-annotations.d.ts +6 -0
- package/dist/tools/with-annotations.js +339 -0
- package/dist/types.d.ts +409 -0
- package/dist/types.js +91 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +18 -0
- package/package.json +107 -0
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
// Server domain service. Owns server-level read endpoints — configuration,
|
|
2
|
+
// message log, transaction log, error-log files. Stateless wrappers; nothing
|
|
3
|
+
// here mutates server state.
|
|
4
|
+
//
|
|
5
|
+
// See docs/ARCHITECTURE.md for the layering.
|
|
6
|
+
import { TM1Error, TM1ErrorCode } from "../../types.js";
|
|
7
|
+
import { rethrowIfSystemicOrDenied } from "./fallback.js";
|
|
8
|
+
// TM1 references the per-run TI error file inside the free-text message, either
|
|
9
|
+
// wrapped in angle brackets (e.g. German `Fehlerdatei: <…log>`) or bare
|
|
10
|
+
// (`see TM1ProcessError_…log`). Both regexes are linear (no nested quantifiers,
|
|
11
|
+
// delimiter excluded from the class) — no ReDoS guard needed for these literals.
|
|
12
|
+
const ANGLE_WRAPPED_LOG = /<([^<>\s]+\.log)>/i;
|
|
13
|
+
const BARE_PROCESS_ERROR_LOG = /TM1ProcessError_[^\s<>'"()]+\.log/i;
|
|
14
|
+
/**
|
|
15
|
+
* Pull the TM1 error log filename out of a message-log entry's free text, so it
|
|
16
|
+
* can be fed straight into `tm1_get_error_log_content(filename=…)`. Returns the
|
|
17
|
+
* exact filename (no surrounding brackets) or undefined when none is mentioned.
|
|
18
|
+
*/
|
|
19
|
+
export function extractErrorFile(message) {
|
|
20
|
+
const angle = message.match(ANGLE_WRAPPED_LOG);
|
|
21
|
+
if (angle)
|
|
22
|
+
return angle[1];
|
|
23
|
+
const bare = message.match(BARE_PROCESS_ERROR_LOG);
|
|
24
|
+
return bare ? bare[0] : undefined;
|
|
25
|
+
}
|
|
26
|
+
// The TransactionLogEntries endpoint scans the whole log server-side and is
|
|
27
|
+
// slow; without log-read rights it can hang until the global request timeout.
|
|
28
|
+
// Before the real (orderby + filtered) query we fire a bare `$top=1` probe —
|
|
29
|
+
// NO $orderby, NO $filter, so TM1 can stop after the first row and the result
|
|
30
|
+
// is at most one entry — bounded by a short timeout to fail fast.
|
|
31
|
+
const TXLOG_PROBE_TIMEOUT_MS = 8000;
|
|
32
|
+
// Per-window query timeout. Each windowed/bounded query runs once (no retry),
|
|
33
|
+
// so a timeout means the range is too large/dense — not a transient blip.
|
|
34
|
+
const TXLOG_QUERY_TIMEOUT_MS = 20000;
|
|
35
|
+
// Expanding lookback windows (ms) for the no-`since` adaptive backfill. We walk
|
|
36
|
+
// backward from the anchor, widening until `top` rows are collected or the last
|
|
37
|
+
// window is exhausted — so an open-ended call never triggers a full-log scan.
|
|
38
|
+
const TXLOG_BACKFILL_WINDOWS_MS = [
|
|
39
|
+
10 * 60_000, // 10 min
|
|
40
|
+
60 * 60_000, // 1 h
|
|
41
|
+
6 * 3_600_000, // 6 h
|
|
42
|
+
24 * 3_600_000, // 1 d
|
|
43
|
+
3 * 86_400_000, // 3 d
|
|
44
|
+
7 * 86_400_000, // 7 d
|
|
45
|
+
30 * 86_400_000, // 30 d
|
|
46
|
+
90 * 86_400_000, // 90 d
|
|
47
|
+
365 * 86_400_000, // 1 y
|
|
48
|
+
];
|
|
49
|
+
// Format an epoch-ms instant as an OData UTC literal (second precision, no ms).
|
|
50
|
+
function epochToOData(ms) {
|
|
51
|
+
return `${new Date(ms).toISOString().slice(0, 19)}Z`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Normalize a user timestamp into an OData v4 DateTimeOffset literal for a
|
|
55
|
+
* TM1 $filter. TM1 rejects a bare `2026-06-08T00:00:00` ("Syntax error … near
|
|
56
|
+
* -06") — the value MUST carry a timezone. Verified against TM1 11.8: only the
|
|
57
|
+
* `Z`-suffixed (or ±hh:mm-offset) form parses. Date-only input expands to
|
|
58
|
+
* start-of-day UTC; a zoneless datetime gets a `Z`; an already-zoned value is
|
|
59
|
+
* left untouched.
|
|
60
|
+
*/
|
|
61
|
+
export function toOdataDateTime(input) {
|
|
62
|
+
let t = input.trim();
|
|
63
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(t))
|
|
64
|
+
t = `${t}T00:00:00`;
|
|
65
|
+
if (!/[zZ]$/.test(t) && !/[+-]\d{2}:\d{2}$/.test(t))
|
|
66
|
+
t = `${t}Z`;
|
|
67
|
+
// Validate before it reaches a $filter. Appending "Z" to whatever arrived
|
|
68
|
+
// turned "yesterday" into "yesterdayZ" and shipped it to TM1, which answers
|
|
69
|
+
// with an opaque OData parse error naming neither the parameter nor the bad
|
|
70
|
+
// value. Rejecting here names both.
|
|
71
|
+
//
|
|
72
|
+
// Shape check FIRST, then Date.parse — Date.parse alone is too permissive to
|
|
73
|
+
// be a gate. It accepts V8's legacy formats, so "08/06/2026" parses happily
|
|
74
|
+
// as 6 August; a caller who meant 8 June would silently get a different day
|
|
75
|
+
// and a plausible-looking, wrong result. Ambiguous input must fail loudly.
|
|
76
|
+
const ISO_DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/;
|
|
77
|
+
if (!ISO_DATETIME.test(t) || Number.isNaN(Date.parse(t))) {
|
|
78
|
+
throw new TM1Error({
|
|
79
|
+
code: TM1ErrorCode.VALIDATION_ERROR,
|
|
80
|
+
message: `Not a usable timestamp: '${input}'. Expected ISO-8601 — ` +
|
|
81
|
+
`'2026-06-08', '2026-06-08T14:30:00', or with a zone ` +
|
|
82
|
+
`('...Z' / '...+02:00'). A value without a zone is read as UTC.`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return t;
|
|
86
|
+
}
|
|
87
|
+
// enc stays plain — it also wraps whole $filter/$orderby clauses below, where
|
|
88
|
+
// the inner string literals are already single-quote-escaped via esc().
|
|
89
|
+
const enc = encodeURIComponent;
|
|
90
|
+
// OData entity-key encoder: double ' per OData literal rules, then percent-encode.
|
|
91
|
+
const encKey = (s) => encodeURIComponent(String(s).replace(/'/g, "''"));
|
|
92
|
+
export class ServerService {
|
|
93
|
+
http;
|
|
94
|
+
constructor(http) {
|
|
95
|
+
this.http = http;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Fetch TM1 server configuration. Merges /Configuration and
|
|
99
|
+
* /ActiveConfiguration; tolerates ActiveConfiguration being absent on
|
|
100
|
+
* older builds.
|
|
101
|
+
*/
|
|
102
|
+
async getInfo() {
|
|
103
|
+
const cfg = await this.http.request("GET", "/api/v1/Configuration");
|
|
104
|
+
let active = {};
|
|
105
|
+
try {
|
|
106
|
+
active = await this.http.request("GET", "/api/v1/ActiveConfiguration");
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Some TM1 versions don't expose ActiveConfiguration — ignore.
|
|
110
|
+
}
|
|
111
|
+
const merged = { ...cfg, ...active };
|
|
112
|
+
delete merged["@odata.context"];
|
|
113
|
+
// v12 (Planning Analytics Engine) omits ProductVersion from the
|
|
114
|
+
// Configuration object body; it is exposed only as a scalar sub-resource.
|
|
115
|
+
// Fall back to it when the inline field is absent (v11 has it inline, so
|
|
116
|
+
// this extra request never fires there).
|
|
117
|
+
let productVersion = String(merged.ProductVersion ?? "");
|
|
118
|
+
if (!productVersion) {
|
|
119
|
+
try {
|
|
120
|
+
const pv = await this.http.request("GET", "/api/v1/Configuration/ProductVersion");
|
|
121
|
+
if (typeof pv.value === "string") {
|
|
122
|
+
productVersion = pv.value;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Scalar sub-resource unavailable — leave version empty.
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
serverName: String(merged.ServerName ?? ""),
|
|
131
|
+
productVersion,
|
|
132
|
+
productEdition: merged.ProductEdition !== undefined
|
|
133
|
+
? String(merged.ProductEdition)
|
|
134
|
+
: undefined,
|
|
135
|
+
adminHost: merged.AdminHost !== undefined ? String(merged.AdminHost) : undefined,
|
|
136
|
+
dataDirectory: merged.DataBaseDirectory !== undefined
|
|
137
|
+
? String(merged.DataBaseDirectory)
|
|
138
|
+
: undefined,
|
|
139
|
+
timeZoneId: merged.TimeZoneID !== undefined ? String(merged.TimeZoneID) : undefined,
|
|
140
|
+
integratedSecurityMode: merged.IntegratedSecurityMode !== undefined
|
|
141
|
+
? String(merged.IntegratedSecurityMode)
|
|
142
|
+
: undefined,
|
|
143
|
+
extra: merged,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get recent TM1 server message log entries (newest first).
|
|
148
|
+
*
|
|
149
|
+
* The text/level/time filters are pushed to the server via `$filter` so a
|
|
150
|
+
* match OLDER than the `top`-row window is still found — filtering only the
|
|
151
|
+
* newest `top` rows client-side produced false negatives ("no error found")
|
|
152
|
+
* whenever the matching entry had scrolled past that window. TM1 v11 supports
|
|
153
|
+
* OData `contains`/`tolower`/`eq`/`ge`/`le` on the MessageLogEntries set.
|
|
154
|
+
*
|
|
155
|
+
* Text match is case-insensitive (tolower on both sides) to preserve the prior
|
|
156
|
+
* client-side `.toLowerCase().includes()` contract. If the server rejects the
|
|
157
|
+
* filtered query (older/limited builds without full string-function support),
|
|
158
|
+
* we fall back to fetching the newest `top` rows and filtering in-process —
|
|
159
|
+
* the same best-effort path as before, so the tool degrades rather than errors.
|
|
160
|
+
*
|
|
161
|
+
* GET /api/v1/MessageLogEntries?$orderby=TimeStamp desc&$top={top}[&$filter=…]
|
|
162
|
+
*/
|
|
163
|
+
async getMessageLog(opts = {}) {
|
|
164
|
+
const top = opts.top ?? 100;
|
|
165
|
+
// Inner-literal single-quote escaping per OData; the whole clause is then
|
|
166
|
+
// URL-encoded with enc() below (mirrors getAuditLog()'s esc()+enc() pattern).
|
|
167
|
+
const esc = (s) => s.replace(/'/g, "''");
|
|
168
|
+
const filters = [];
|
|
169
|
+
if (opts.filter)
|
|
170
|
+
filters.push(`contains(tolower(Message),'${esc(opts.filter.toLowerCase())}')`);
|
|
171
|
+
if (opts.level)
|
|
172
|
+
filters.push(`toupper(Level) eq '${esc(opts.level.toUpperCase())}'`);
|
|
173
|
+
if (opts.logger)
|
|
174
|
+
filters.push(`Logger eq '${esc(opts.logger)}'`);
|
|
175
|
+
if (opts.since)
|
|
176
|
+
filters.push(`TimeStamp ge ${toOdataDateTime(opts.since)}`);
|
|
177
|
+
if (opts.until)
|
|
178
|
+
filters.push(`TimeStamp le ${toOdataDateTime(opts.until)}`);
|
|
179
|
+
const qs = [`$orderby=${enc("TimeStamp desc")}`, `$top=${top}`];
|
|
180
|
+
if (filters.length > 0)
|
|
181
|
+
qs.push(`$filter=${enc(filters.join(" and "))}`);
|
|
182
|
+
const map = (rows) => rows.map((e) => {
|
|
183
|
+
const message = e.Message ?? e.Text ?? "";
|
|
184
|
+
const errorFile = extractErrorFile(message);
|
|
185
|
+
return {
|
|
186
|
+
timestamp: e.TimeStamp ?? e.Timestamp ?? "",
|
|
187
|
+
level: (e.Level ?? "").toUpperCase(),
|
|
188
|
+
message,
|
|
189
|
+
...(errorFile ? { errorFile } : {}),
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
if (filters.length === 0) {
|
|
193
|
+
const response = await this.http.request("GET", `/api/v1/MessageLogEntries?${qs.join("&")}`);
|
|
194
|
+
return map(response.value);
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const response = await this.http.request("GET", `/api/v1/MessageLogEntries?${qs.join("&")}`);
|
|
198
|
+
return map(response.value);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
// Systemic transport/auth failures and permission denials must surface —
|
|
202
|
+
// only a server-side rejection of the filter expression itself should
|
|
203
|
+
// trigger the degraded client-side fallback.
|
|
204
|
+
rethrowIfSystemicOrDenied(err);
|
|
205
|
+
const response = await this.http.request("GET", `/api/v1/MessageLogEntries?$orderby=${enc("TimeStamp desc")}&$top=${top}`);
|
|
206
|
+
// Degraded path: re-apply the FULL filter set client-side over the
|
|
207
|
+
// newest-`top` window. Filtering raw rows (pre-map) so Logger/TimeStamp
|
|
208
|
+
// are available — otherwise since/until/logger would be silently dropped
|
|
209
|
+
// and out-of-range rows returned mislabeled as matches.
|
|
210
|
+
let rows = response.value;
|
|
211
|
+
if (opts.filter) {
|
|
212
|
+
const needle = opts.filter.toLowerCase();
|
|
213
|
+
rows = rows.filter((e) => (e.Message ?? e.Text ?? "").toLowerCase().includes(needle));
|
|
214
|
+
}
|
|
215
|
+
if (opts.level) {
|
|
216
|
+
const want = opts.level.toUpperCase();
|
|
217
|
+
rows = rows.filter((e) => (e.Level ?? "").toUpperCase() === want);
|
|
218
|
+
}
|
|
219
|
+
if (opts.logger) {
|
|
220
|
+
rows = rows.filter((e) => e.Logger === opts.logger);
|
|
221
|
+
}
|
|
222
|
+
if (opts.since) {
|
|
223
|
+
const from = Date.parse(opts.since);
|
|
224
|
+
if (!Number.isNaN(from)) {
|
|
225
|
+
rows = rows.filter((e) => {
|
|
226
|
+
const ts = Date.parse(e.TimeStamp ?? e.Timestamp ?? "");
|
|
227
|
+
return !Number.isNaN(ts) && ts >= from;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (opts.until) {
|
|
232
|
+
const to = Date.parse(opts.until);
|
|
233
|
+
if (!Number.isNaN(to)) {
|
|
234
|
+
rows = rows.filter((e) => {
|
|
235
|
+
const ts = Date.parse(e.TimeStamp ?? e.Timestamp ?? "");
|
|
236
|
+
return !Number.isNaN(ts) && ts <= to;
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return map(rows);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Fetch recent TM1 audit log entries (metadata/security changes), newest
|
|
245
|
+
* first. Requires AuditLogOn=T in tm1s.cfg — with auditing disabled the
|
|
246
|
+
* entity set is empty.
|
|
247
|
+
* GET /api/v1/AuditLogEntries
|
|
248
|
+
*/
|
|
249
|
+
async getAuditLog(opts) {
|
|
250
|
+
const esc = (s) => s.replace(/'/g, "''");
|
|
251
|
+
const filters = [];
|
|
252
|
+
if (opts.user)
|
|
253
|
+
filters.push(`UserName eq '${esc(opts.user)}'`);
|
|
254
|
+
if (opts.objectType)
|
|
255
|
+
filters.push(`ObjectType eq '${esc(opts.objectType)}'`);
|
|
256
|
+
if (opts.objectName)
|
|
257
|
+
filters.push(`ObjectName eq '${esc(opts.objectName)}'`);
|
|
258
|
+
if (opts.since)
|
|
259
|
+
filters.push(`TimeStamp ge ${toOdataDateTime(opts.since)}`);
|
|
260
|
+
if (opts.until)
|
|
261
|
+
filters.push(`TimeStamp le ${toOdataDateTime(opts.until)}`);
|
|
262
|
+
const top = opts.top ?? 100;
|
|
263
|
+
const qs = [`$top=${top}`, `$orderby=${enc("TimeStamp desc")}`];
|
|
264
|
+
if (filters.length > 0)
|
|
265
|
+
qs.push(`$filter=${enc(filters.join(" and "))}`);
|
|
266
|
+
if (opts.includeDetails)
|
|
267
|
+
qs.push("$expand=AuditDetails");
|
|
268
|
+
const response = await this.http.request("GET", `/api/v1/AuditLogEntries?${qs.join("&")}`);
|
|
269
|
+
const mapDetail = (d) => ({
|
|
270
|
+
id: d.ID ?? 0,
|
|
271
|
+
timestamp: d.TimeStamp ?? "",
|
|
272
|
+
user: d.UserName ?? "",
|
|
273
|
+
description: d.Description ?? "",
|
|
274
|
+
objectType: d.ObjectType ?? "",
|
|
275
|
+
objectName: d.ObjectName ?? "",
|
|
276
|
+
});
|
|
277
|
+
return response.value.map((e) => {
|
|
278
|
+
const entry = mapDetail(e);
|
|
279
|
+
if (e.AuditDetails !== undefined)
|
|
280
|
+
entry.details = e.AuditDetails.map(mapDetail);
|
|
281
|
+
return entry;
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Fetch recent TM1 transaction log entries (cell writes).
|
|
286
|
+
* GET /api/v1/TransactionLogEntries
|
|
287
|
+
*/
|
|
288
|
+
async getTransactionLog(opts) {
|
|
289
|
+
const top = opts.top ?? 100;
|
|
290
|
+
// Preflight: bare $top=1 (no orderby/filter) — cheap reachability/permission
|
|
291
|
+
// gate that fails fast instead of hanging.
|
|
292
|
+
await this.probeTransactionLog();
|
|
293
|
+
// Explicit lower bound → a single bounded query [since, until]. Coverage is
|
|
294
|
+
// well-defined by the bound: everything in the span is returned.
|
|
295
|
+
if (opts.since !== undefined) {
|
|
296
|
+
const entries = await this.queryTransactionLog({
|
|
297
|
+
top,
|
|
298
|
+
cubeName: opts.cubeName,
|
|
299
|
+
user: opts.user,
|
|
300
|
+
since: opts.since,
|
|
301
|
+
until: opts.until,
|
|
302
|
+
});
|
|
303
|
+
return {
|
|
304
|
+
entries,
|
|
305
|
+
coverage: "complete",
|
|
306
|
+
scannedFrom: toOdataDateTime(opts.since),
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
// No lower bound → adaptive backward windowing from `until` (or now). An
|
|
310
|
+
// unbounded TransactionLogEntries scan takes minutes-to-hours; instead we
|
|
311
|
+
// probe expanding windows and stop as soon as we have `top` rows. If a wide
|
|
312
|
+
// window times out we keep the rows already collected rather than failing.
|
|
313
|
+
// Coverage: "partial" if we stopped because `top` filled or a window failed
|
|
314
|
+
// (older matching rows may exist earlier); "complete" if windows exhausted.
|
|
315
|
+
const anchorMs = opts.until !== undefined
|
|
316
|
+
? Date.parse(toOdataDateTime(opts.until))
|
|
317
|
+
: Date.now();
|
|
318
|
+
let collected = [];
|
|
319
|
+
let scannedFromMs = anchorMs;
|
|
320
|
+
for (const windowMs of TXLOG_BACKFILL_WINDOWS_MS) {
|
|
321
|
+
const floorMs = anchorMs - windowMs;
|
|
322
|
+
let entries;
|
|
323
|
+
try {
|
|
324
|
+
entries = await this.queryTransactionLog({
|
|
325
|
+
top,
|
|
326
|
+
cubeName: opts.cubeName,
|
|
327
|
+
user: opts.user,
|
|
328
|
+
since: epochToOData(floorMs),
|
|
329
|
+
until: opts.until,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
// Systemic transport/auth failures (CONNECTION_FAILED, AUTH_FAILED,
|
|
334
|
+
// LOCK_TIMEOUT) AND permission denials must surface — swallowing them
|
|
335
|
+
// would return an empty or partial window as if the range simply held no
|
|
336
|
+
// data (or as if a denied cube were empty). A window timeout (TM1_ERROR
|
|
337
|
+
// from queryTransactionLog) is expected and just stops widening — but we
|
|
338
|
+
// stopped short of exhausting the span, so coverage is partial.
|
|
339
|
+
rethrowIfSystemicOrDenied(err);
|
|
340
|
+
return {
|
|
341
|
+
entries: collected,
|
|
342
|
+
coverage: "partial",
|
|
343
|
+
scannedFrom: epochToOData(scannedFromMs),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
scannedFromMs = floorMs;
|
|
347
|
+
collected = entries;
|
|
348
|
+
if (entries.length >= top) {
|
|
349
|
+
return {
|
|
350
|
+
entries,
|
|
351
|
+
coverage: "partial",
|
|
352
|
+
scannedFrom: epochToOData(floorMs),
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
entries: collected,
|
|
358
|
+
coverage: "complete",
|
|
359
|
+
scannedFrom: epochToOData(scannedFromMs),
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Single bounded TransactionLogEntries query. Runs once (retry disabled) under
|
|
364
|
+
* a dedicated timeout: the endpoint is deterministically slow, so a timeout
|
|
365
|
+
* means "range too large", not a transient blip. Our own timeout (the
|
|
366
|
+
* controller abort) and other non-systemic failures become an actionable
|
|
367
|
+
* "narrow the range" error; systemic transport/auth failures propagate
|
|
368
|
+
* unmasked and permission denials surface as-is.
|
|
369
|
+
*/
|
|
370
|
+
async queryTransactionLog(q) {
|
|
371
|
+
const filters = [];
|
|
372
|
+
if (q.cubeName)
|
|
373
|
+
filters.push(`Cube eq '${q.cubeName.replace(/'/g, "''")}'`);
|
|
374
|
+
if (q.user)
|
|
375
|
+
filters.push(`User eq '${q.user.replace(/'/g, "''")}'`);
|
|
376
|
+
if (q.since)
|
|
377
|
+
filters.push(`TimeStamp ge ${toOdataDateTime(q.since)}`);
|
|
378
|
+
if (q.until)
|
|
379
|
+
filters.push(`TimeStamp le ${toOdataDateTime(q.until)}`);
|
|
380
|
+
const qs = [`$top=${q.top}`, `$orderby=TimeStamp desc`];
|
|
381
|
+
if (filters.length > 0)
|
|
382
|
+
qs.push(`$filter=${enc(filters.join(" and "))}`);
|
|
383
|
+
const path = `/api/v1/TransactionLogEntries?${qs.join("&")}`;
|
|
384
|
+
const controller = new AbortController();
|
|
385
|
+
const timer = setTimeout(() => controller.abort(), TXLOG_QUERY_TIMEOUT_MS);
|
|
386
|
+
try {
|
|
387
|
+
const response = await this.http.request("GET", path, undefined, { signal: controller.signal, retry: false });
|
|
388
|
+
return response.value.map((e) => ({
|
|
389
|
+
timestamp: e.TimeStamp ?? "",
|
|
390
|
+
user: e.User ?? "",
|
|
391
|
+
cubeName: e.Cube ?? "",
|
|
392
|
+
elements: e.Tuple ?? [],
|
|
393
|
+
oldValue: e.OldValue ?? null,
|
|
394
|
+
newValue: e.NewValue ?? null,
|
|
395
|
+
}));
|
|
396
|
+
}
|
|
397
|
+
catch (err) {
|
|
398
|
+
// Our own dedicated timeout aborts via the controller and surfaces as a
|
|
399
|
+
// raw (non-TM1) abort — that IS the "range too large" signal. For every
|
|
400
|
+
// other error, systemic transport/auth failures (CONNECTION_FAILED,
|
|
401
|
+
// AUTH_FAILED, LOCK_TIMEOUT) and unexpected non-TM1 throws must propagate
|
|
402
|
+
// unmasked, and a permission denial stays actionable; only then do we fall
|
|
403
|
+
// through and treat the failure as an actionable "narrow the range" error.
|
|
404
|
+
if (!controller.signal.aborted) {
|
|
405
|
+
rethrowIfSystemicOrDenied(err);
|
|
406
|
+
}
|
|
407
|
+
throw new TM1Error({
|
|
408
|
+
code: TM1ErrorCode.TM1_ERROR,
|
|
409
|
+
message: `Transaction log query exceeded ${TXLOG_QUERY_TIMEOUT_MS / 1000}s — the time range is too large or dense.`,
|
|
410
|
+
endpoint: path,
|
|
411
|
+
details: err instanceof Error ? err.message : String(err),
|
|
412
|
+
hint: "Bound the scan with a narrower since/until (from-to) range, or add cubeName/user.",
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
finally {
|
|
416
|
+
clearTimeout(timer);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Cheap reachability/permission probe for the transaction log. A bare
|
|
421
|
+
* `$top=1` (no $orderby/$filter) returns at most one row so TM1 can short-
|
|
422
|
+
* circuit; a dedicated short-timeout AbortController caps the wait. That
|
|
423
|
+
* timeout (and other non-systemic failures) becomes an actionable TM1_ERROR;
|
|
424
|
+
* permission denials surface as-is and systemic transport/auth failures
|
|
425
|
+
* (e.g. CONNECTION_FAILED) propagate unmasked.
|
|
426
|
+
*/
|
|
427
|
+
async probeTransactionLog() {
|
|
428
|
+
const controller = new AbortController();
|
|
429
|
+
const timer = setTimeout(() => controller.abort(), TXLOG_PROBE_TIMEOUT_MS);
|
|
430
|
+
try {
|
|
431
|
+
await this.http.request("GET", "/api/v1/TransactionLogEntries?$top=1", undefined, { signal: controller.signal });
|
|
432
|
+
}
|
|
433
|
+
catch (err) {
|
|
434
|
+
// Our own probe timeout aborts via the controller and yields the friendly
|
|
435
|
+
// preflight message. For every other error, systemic transport/auth
|
|
436
|
+
// failures (CONNECTION_FAILED, AUTH_FAILED, LOCK_TIMEOUT) and unexpected
|
|
437
|
+
// non-TM1 throws must propagate unmasked, and a permission denial stays
|
|
438
|
+
// actionable (fail fast); only then do we wrap as a TM1_ERROR preflight.
|
|
439
|
+
if (!controller.signal.aborted) {
|
|
440
|
+
rethrowIfSystemicOrDenied(err);
|
|
441
|
+
}
|
|
442
|
+
throw new TM1Error({
|
|
443
|
+
code: TM1ErrorCode.TM1_ERROR,
|
|
444
|
+
message: `Transaction log preflight failed (timeout ${TXLOG_PROBE_TIMEOUT_MS / 1000}s): the endpoint scans the whole log and may hang or be denied without log-read rights.`,
|
|
445
|
+
endpoint: "/api/v1/TransactionLogEntries",
|
|
446
|
+
details: err instanceof Error ? err.message : String(err),
|
|
447
|
+
hint: "Narrow the query with `since`, `cubeName`, or `user`, or verify the account has transaction-log read rights.",
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
finally {
|
|
451
|
+
clearTimeout(timer);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* List TI process error log files.
|
|
456
|
+
*
|
|
457
|
+
* TM1 v11 OData exposes only `Filename` on this entity set (no LastUpdated /
|
|
458
|
+
* $select / $orderby support). Sorting is filename-descending — filenames
|
|
459
|
+
* embed a yyyymmddhhmmss timestamp, so lexical desc sort matches
|
|
460
|
+
* chronological newest-first. Filters (processName, since, top) are applied
|
|
461
|
+
* client-side.
|
|
462
|
+
*/
|
|
463
|
+
async listErrorLogFiles(opts = {}) {
|
|
464
|
+
const top = opts.top ?? 50;
|
|
465
|
+
const response = await this.http.request("GET", "/api/v1/ErrorLogFiles");
|
|
466
|
+
let entries = response.value
|
|
467
|
+
.map((e) => ({ filename: e.Filename ?? "" }))
|
|
468
|
+
.filter((e) => e.filename);
|
|
469
|
+
if (opts.processName) {
|
|
470
|
+
const proc = opts.processName.toLowerCase();
|
|
471
|
+
// TM1 v11+ pattern with session hash: TM1ProcessError_<ts>_<id>_<proc>_<hash>.log
|
|
472
|
+
// TM1 pattern without hash: TM1ProcessError_<ts>_<id>_<proc>.log
|
|
473
|
+
// Legacy/manual pattern: <proc>_<ts>.log
|
|
474
|
+
entries = entries.filter((e) => {
|
|
475
|
+
const f = e.filename.toLowerCase();
|
|
476
|
+
return (f === proc ||
|
|
477
|
+
f.startsWith(`${proc}_`) ||
|
|
478
|
+
f.endsWith(`_${proc}.log`) ||
|
|
479
|
+
f.includes(`_${proc}_`));
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
if (opts.since) {
|
|
483
|
+
const sinceCompact = opts.since.replace(/[^0-9]/g, "").slice(0, 14);
|
|
484
|
+
if (sinceCompact.length >= 8) {
|
|
485
|
+
entries = entries.filter((e) => {
|
|
486
|
+
const m = e.filename.match(/(?:TM1ProcessError_|_)(\d{14})/) ??
|
|
487
|
+
e.filename.match(/_(\d{8,14})\.log$/i);
|
|
488
|
+
return m ? m[1] >= sinceCompact.slice(0, m[1].length) : true;
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
entries.sort((a, b) => a.filename < b.filename ? 1 : a.filename > b.filename ? -1 : 0);
|
|
493
|
+
return entries.slice(0, top);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Fetch the raw text content of a single TI error log file.
|
|
497
|
+
* GET /api/v1/ErrorLogFiles('<filename>')/Content
|
|
498
|
+
*/
|
|
499
|
+
async getErrorLogContent(filename) {
|
|
500
|
+
const path = `/api/v1/ErrorLogFiles('${encKey(filename)}')/Content`;
|
|
501
|
+
return await this.http.requestRaw("GET", path);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
//# sourceMappingURL=server-service.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Subset, SubsetCreate } from "../../types.js";
|
|
2
|
+
import type { TM1HttpClient } from "../http.js";
|
|
3
|
+
export declare class SubsetService {
|
|
4
|
+
private readonly http;
|
|
5
|
+
constructor(http: TM1HttpClient);
|
|
6
|
+
/**
|
|
7
|
+
* List public + private subsets of a hierarchy.
|
|
8
|
+
* GET /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets|PrivateSubsets
|
|
9
|
+
*/
|
|
10
|
+
list(dimensionName: string, hierarchyName: string): Promise<Subset[]>;
|
|
11
|
+
/**
|
|
12
|
+
* Get a single subset incl. resolved Elements.
|
|
13
|
+
* GET /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets('{s}')?$expand=Elements($select=Name)
|
|
14
|
+
*/
|
|
15
|
+
get(dimensionName: string, hierarchyName: string, subsetName: string, isPrivate?: boolean): Promise<Subset>;
|
|
16
|
+
/**
|
|
17
|
+
* Create a public subset. Either MDX-based (expression) or static
|
|
18
|
+
* (elements). Mixed/empty inputs throw VALIDATION_ERROR.
|
|
19
|
+
* POST /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets
|
|
20
|
+
*/
|
|
21
|
+
create(dimensionName: string, hierarchyName: string, subset: SubsetCreate): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Update an existing public subset.
|
|
24
|
+
* PATCH /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets('{s}')
|
|
25
|
+
*/
|
|
26
|
+
update(dimensionName: string, hierarchyName: string, subsetName: string, update: {
|
|
27
|
+
expression?: string | undefined;
|
|
28
|
+
elements?: string[] | undefined;
|
|
29
|
+
alias?: string | undefined;
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Delete a public subset.
|
|
33
|
+
* DELETE /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets('{s}')
|
|
34
|
+
*/
|
|
35
|
+
delete(dimensionName: string, hierarchyName: string, subsetName: string): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=subset-service.d.ts.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Subset domain service. Owns the OData calls under
|
|
2
|
+
// /api/v1/Dimensions('{d}')/Hierarchies('{h}')/{Subsets|PrivateSubsets} —
|
|
3
|
+
// list, get, create, update, delete. Subsets are either MDX-based
|
|
4
|
+
// (Expression) or static (Elements list); both shapes are handled here.
|
|
5
|
+
//
|
|
6
|
+
// See docs/ARCHITECTURE.md for the layering.
|
|
7
|
+
import { TM1Error, TM1ErrorCode } from "../../types.js";
|
|
8
|
+
import { rethrowIfSystemic } from "./fallback.js";
|
|
9
|
+
// OData key encoder: double ' per OData literal rules, then percent-encode.
|
|
10
|
+
const enc = (s) => encodeURIComponent(String(s).replace(/'/g, "''"));
|
|
11
|
+
export class SubsetService {
|
|
12
|
+
http;
|
|
13
|
+
constructor(http) {
|
|
14
|
+
this.http = http;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* List public + private subsets of a hierarchy.
|
|
18
|
+
* GET /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets|PrivateSubsets
|
|
19
|
+
*/
|
|
20
|
+
async list(dimensionName, hierarchyName) {
|
|
21
|
+
const result = [];
|
|
22
|
+
const fetchScope = async (segment, isPrivate) => {
|
|
23
|
+
try {
|
|
24
|
+
const path = `/api/v1/Dimensions('${enc(dimensionName)}')/Hierarchies('${enc(hierarchyName)}')/${segment}?$select=Name,Expression,Alias`;
|
|
25
|
+
const response = await this.http.request("GET", path);
|
|
26
|
+
for (const s of response.value) {
|
|
27
|
+
result.push({
|
|
28
|
+
name: s.Name,
|
|
29
|
+
dimensionName,
|
|
30
|
+
hierarchyName,
|
|
31
|
+
private: isPrivate,
|
|
32
|
+
expression: s.Expression || undefined,
|
|
33
|
+
elements: [],
|
|
34
|
+
alias: s.Alias || undefined,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
rethrowIfSystemic(e);
|
|
40
|
+
// scope may not exist
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
await fetchScope("Subsets", false);
|
|
44
|
+
await fetchScope("PrivateSubsets", true);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get a single subset incl. resolved Elements.
|
|
49
|
+
* GET /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets('{s}')?$expand=Elements($select=Name)
|
|
50
|
+
*/
|
|
51
|
+
async get(dimensionName, hierarchyName, subsetName, isPrivate = false) {
|
|
52
|
+
const segment = isPrivate ? "PrivateSubsets" : "Subsets";
|
|
53
|
+
const path = `/api/v1/Dimensions('${enc(dimensionName)}')/Hierarchies('${enc(hierarchyName)}')/${segment}('${enc(subsetName)}')?$expand=Elements($select=Name)&$select=Name,Expression,Alias`;
|
|
54
|
+
const response = await this.http.request("GET", path);
|
|
55
|
+
return {
|
|
56
|
+
name: response.Name,
|
|
57
|
+
dimensionName,
|
|
58
|
+
hierarchyName,
|
|
59
|
+
private: isPrivate,
|
|
60
|
+
expression: response.Expression || undefined,
|
|
61
|
+
elements: (response.Elements ?? []).map((e) => e.Name),
|
|
62
|
+
alias: response.Alias || undefined,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a public subset. Either MDX-based (expression) or static
|
|
67
|
+
* (elements). Mixed/empty inputs throw VALIDATION_ERROR.
|
|
68
|
+
* POST /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets
|
|
69
|
+
*/
|
|
70
|
+
async create(dimensionName, hierarchyName, subset) {
|
|
71
|
+
const path = `/api/v1/Dimensions('${enc(dimensionName)}')/Hierarchies('${enc(hierarchyName)}')/Subsets`;
|
|
72
|
+
if (subset.expression && subset.elements && subset.elements.length > 0) {
|
|
73
|
+
throw new TM1Error({
|
|
74
|
+
code: TM1ErrorCode.VALIDATION_ERROR,
|
|
75
|
+
message: "Subset must be either MDX-based (expression) OR static (elements), not both.",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (!subset.expression &&
|
|
79
|
+
(!subset.elements || subset.elements.length === 0)) {
|
|
80
|
+
throw new TM1Error({
|
|
81
|
+
code: TM1ErrorCode.VALIDATION_ERROR,
|
|
82
|
+
message: "Subset requires either expression (MDX) or non-empty elements list.",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const body = { Name: subset.name };
|
|
86
|
+
if (subset.alias)
|
|
87
|
+
body.Alias = subset.alias;
|
|
88
|
+
if (subset.expression) {
|
|
89
|
+
body.Expression = subset.expression;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
body["Elements@odata.bind"] = subset.elements.map((e) => `Dimensions('${enc(dimensionName)}')/Hierarchies('${enc(hierarchyName)}')/Elements('${enc(e)}')`);
|
|
93
|
+
}
|
|
94
|
+
await this.http.request("POST", path, body);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Update an existing public subset.
|
|
98
|
+
* PATCH /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets('{s}')
|
|
99
|
+
*/
|
|
100
|
+
async update(dimensionName, hierarchyName, subsetName, update) {
|
|
101
|
+
const path = `/api/v1/Dimensions('${enc(dimensionName)}')/Hierarchies('${enc(hierarchyName)}')/Subsets('${enc(subsetName)}')`;
|
|
102
|
+
const body = {};
|
|
103
|
+
if (update.alias !== undefined)
|
|
104
|
+
body.Alias = update.alias;
|
|
105
|
+
if (update.expression !== undefined) {
|
|
106
|
+
body.Expression = update.expression;
|
|
107
|
+
}
|
|
108
|
+
else if (update.elements !== undefined) {
|
|
109
|
+
body.Expression = "";
|
|
110
|
+
body["Elements@odata.bind"] = update.elements.map((e) => `Dimensions('${enc(dimensionName)}')/Hierarchies('${enc(hierarchyName)}')/Elements('${enc(e)}')`);
|
|
111
|
+
}
|
|
112
|
+
await this.http.request("PATCH", path, body);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Delete a public subset.
|
|
116
|
+
* DELETE /api/v1/Dimensions('{d}')/Hierarchies('{h}')/Subsets('{s}')
|
|
117
|
+
*/
|
|
118
|
+
async delete(dimensionName, hierarchyName, subsetName) {
|
|
119
|
+
await this.http.request("DELETE", `/api/v1/Dimensions('${enc(dimensionName)}')/Hierarchies('${enc(hierarchyName)}')/Subsets('${enc(subsetName)}')`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=subset-service.js.map
|