@hotmeshio/long-tail 0.12.1 → 0.13.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/README.md +1 -0
- package/build/api/escalations/helpers.js +4 -2
- package/build/api/settings.js +3 -0
- package/build/services/agent/index.d.ts +11 -0
- package/build/services/agent/index.js +32 -0
- package/build/services/agent/sql.d.ts +7 -0
- package/build/services/agent/sql.js +32 -1
- package/build/services/agent/subscription-sql.d.ts +6 -0
- package/build/services/agent/subscription-sql.js +32 -1
- package/build/services/agent/subscriptions.d.ts +6 -0
- package/build/services/agent/subscriptions.js +23 -0
- package/build/services/config/index.d.ts +1 -1
- package/build/services/config/index.js +2 -1
- package/build/services/config/write.d.ts +10 -0
- package/build/services/config/write.js +49 -2
- package/build/services/domain/seed.d.ts +12 -5
- package/build/services/domain/seed.js +25 -6
- package/build/services/mcp/db.d.ts +16 -0
- package/build/services/mcp/db.js +24 -0
- package/build/services/mcp/sql.d.ts +8 -0
- package/build/services/mcp/sql.js +24 -1
- package/build/services/role/seed.d.ts +21 -0
- package/build/services/role/seed.js +113 -0
- package/build/services/role/sql.d.ts +8 -0
- package/build/services/role/sql.js +24 -1
- package/build/services/topics/index.d.ts +2 -0
- package/build/services/topics/index.js +7 -0
- package/build/services/topics/sql.d.ts +2 -0
- package/build/services/topics/sql.js +5 -1
- package/build/services/topics/system-topics.d.ts +3 -2
- package/build/services/topics/system-topics.js +4 -3
- package/build/services/user/index.d.ts +1 -1
- package/build/services/user/index.js +2 -1
- package/build/services/user/roles.d.ts +8 -0
- package/build/services/user/roles.js +29 -0
- package/build/services/user/sql.d.ts +6 -0
- package/build/services/user/sql.js +9 -1
- package/build/services/user/sso-provision.js +14 -3
- package/build/start/apply-report.d.ts +26 -0
- package/build/start/apply-report.js +65 -0
- package/build/start/config.js +8 -1
- package/build/start/workers.js +170 -33
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/auth.d.ts +27 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/startup.d.ts +108 -4
- package/dashboard/dist/assets/{AdminDashboard-DpTZG5EL.js → AdminDashboard-D2unnS2b.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DpTZG5EL.js.map → AdminDashboard-D2unnS2b.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-DVTL0NvC.js → AgentConfigPage-CBkf403g.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-DVTL0NvC.js.map → AgentConfigPage-CBkf403g.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-DOLKNPJl.js → AgentDetailPage-CAIU3yzo.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-DOLKNPJl.js.map → AgentDetailPage-CAIU3yzo.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-DiOZu6Xb.js → AgentsPage-qP9fWMyT.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-DiOZu6Xb.js.map → AgentsPage-qP9fWMyT.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-CY5lfx27.js → AvailableEscalationsPage-DvWaiafI.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-CY5lfx27.js.map → AvailableEscalationsPage-DvWaiafI.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-ButjLJr2.js → BotPicker-BN-MKITV.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-ButjLJr2.js.map → BotPicker-BN-MKITV.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CW_r2OlX.js → CapabilitiesPage-CJfmWokN.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CW_r2OlX.js.map → CapabilitiesPage-CJfmWokN.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BOGRyCfm.js → CollapsibleSection-BvMHlHyt.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BOGRyCfm.js.map → CollapsibleSection-BvMHlHyt.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-UcHYZSg1.js → CountdownTimer-By4rbMDN.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-UcHYZSg1.js.map → CountdownTimer-By4rbMDN.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-A7OFYVsX.js → CredentialsPage-2TvvRwGJ.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-A7OFYVsX.js.map → CredentialsPage-2TvvRwGJ.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-Dve2Udsm.js → CronLabel-HxmsDSnV.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Dve2Udsm.js.map → CronLabel-HxmsDSnV.js.map} +1 -1
- package/dashboard/dist/assets/{CustomDurationPicker-BoPrA-Em.js → CustomDurationPicker-8Ao-1pKA.js} +2 -2
- package/dashboard/dist/assets/{CustomDurationPicker-BoPrA-Em.js.map → CustomDurationPicker-8Ao-1pKA.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-B114P5mb.js → ElapsedCell-BkRu9Xpd.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-B114P5mb.js.map → ElapsedCell-BkRu9Xpd.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-BqDWyOa9.js → EntityTimelinePanel--E6hLMCM.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-BqDWyOa9.js.map → EntityTimelinePanel--E6hLMCM.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-DyyTyghx.js → EscalationListSchemaPage-CdFtqEEX.js} +2 -2
- package/dashboard/dist/assets/{EscalationListSchemaPage-DyyTyghx.js.map → EscalationListSchemaPage-CdFtqEEX.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-DLQG6EXQ.js → EscalationSchemaPage-BsjS2axz.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-DLQG6EXQ.js.map → EscalationSchemaPage-BsjS2axz.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-RrbkkEU0.js → EscalationsOverview-FL-xteVc.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-RrbkkEU0.js.map → EscalationsOverview-FL-xteVc.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DOxubt7O.js → EventTable-BOcgZ78i.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DOxubt7O.js.map → EventTable-BOcgZ78i.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-y659Gc3X.js → FilterBar-DfCiCmm-.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-y659Gc3X.js.map → FilterBar-DfCiCmm-.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-oHLgSAl6.js → GraphInvokePage-DfVeiN-8.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-oHLgSAl6.js.map → GraphInvokePage-DfVeiN-8.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-C9FUpD7x.js → HomePage-C2IhF9WB.js} +2 -2
- package/dashboard/dist/assets/{HomePage-C9FUpD7x.js.map → HomePage-C2IhF9WB.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-DfpSgWYU.js → ListToolbar-DA0PTOl5.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-DfpSgWYU.js.map → ListToolbar-DA0PTOl5.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-6Ubpr9QS.js → McpOverview-DstPch5M.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-6Ubpr9QS.js.map → McpOverview-DstPch5M.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-DFt-vQEp.js → McpQueryDetailPage-Csv0PKE0.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-DFt-vQEp.js.map → McpQueryDetailPage-Csv0PKE0.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-DQiG0AE3.js → McpQueryPage-DxmqCkly.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-DQiG0AE3.js.map → McpQueryPage-DxmqCkly.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-BgsSegyP.js → McpRunDetailPage-CcJOlp_B.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-BgsSegyP.js.map → McpRunDetailPage-CcJOlp_B.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-tCMxspqS.js → McpRunsPage-BZCR043j.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-tCMxspqS.js.map → McpRunsPage-BZCR043j.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-DUaRmEPa.js → OperationsPage-DMsPXITh.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-DUaRmEPa.js.map → OperationsPage-DMsPXITh.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-CayyjMcf.js → OperatorDashboard-DSloftQ5.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-CayyjMcf.js.map → OperatorDashboard-DSloftQ5.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-DBcxfdbN.js → PersonaDetailPage-jDVRCLbU.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-DBcxfdbN.js.map → PersonaDetailPage-jDVRCLbU.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-DPq0HQAB.js → PersonasPage-DnDDwXoy.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-DPq0HQAB.js.map → PersonasPage-DnDDwXoy.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-QQZNNNMw.js → ProcessDetailPage-CfAUU6q2.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-QQZNNNMw.js.map → ProcessDetailPage-CfAUU6q2.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-UKQMJ4Te.js → ProcessesListPage-CnAXzaVv.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-UKQMJ4Te.js.map → ProcessesListPage-CnAXzaVv.js.map} +1 -1
- package/dashboard/dist/assets/{RoleDetailPage-DT-3sSRD.js → RoleDetailPage-Dg1p6Qz_.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-DT-3sSRD.js.map → RoleDetailPage-Dg1p6Qz_.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-DZg4niqL.js → RolesPage-DeRVQux8.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-DZg4niqL.js.map → RolesPage-DeRVQux8.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-DkcNR7L6.js → RunAsSelector-BFNqQGuG.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-DkcNR7L6.js.map → RunAsSelector-BFNqQGuG.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-U-alpwWF.js → ScanCodesPage-D0GOdk5m.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-U-alpwWF.js.map → ScanCodesPage-D0GOdk5m.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-lXwlcraS.js → ScanSchemeDetailPage-vFqoe_P4.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-lXwlcraS.js.map → ScanSchemeDetailPage-vFqoe_P4.js.map} +1 -1
- package/dashboard/dist/assets/{ScanStationPage-DYMiTp-v.js → ScanStationPage-DH1ynTX9.js} +2 -2
- package/dashboard/dist/assets/{ScanStationPage-DYMiTp-v.js.map → ScanStationPage-DH1ynTX9.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-D896Wquq.js → StickyPagination-B99hVu95.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-D896Wquq.js.map → StickyPagination-B99hVu95.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-DIh5qEGJ.js → StreamMessageDetail-DcDGISrv.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-DIh5qEGJ.js.map → StreamMessageDetail-DcDGISrv.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-B8SucVj5.js → SwimlaneTimeline-BP3mSQAg.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-B8SucVj5.js.map → SwimlaneTimeline-BP3mSQAg.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-Di-z_ZE2.js → TaskDetailPage-_XWLJzt-.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-Di-z_ZE2.js.map → TaskDetailPage-_XWLJzt-.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-ClHGEdin.js → TasksListPage-iGriKiO2.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-ClHGEdin.js.map → TasksListPage-iGriKiO2.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BSDHd9Xo.js → TimeAgo-BO33VeFl.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BSDHd9Xo.js.map → TimeAgo-BO33VeFl.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-WQL3FxWl.js → TimestampCell-KAjX7w35.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-WQL3FxWl.js.map → TimestampCell-KAjX7w35.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-IVIkqZTi.js → ToolTestPanel-BchG2yC6.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-IVIkqZTi.js.map → ToolTestPanel-BchG2yC6.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-BOasQo68.js → TopicDetailPage-BaK8H0o1.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-BOasQo68.js.map → TopicDetailPage-BaK8H0o1.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-DV_orf_V.js → TopicsPage-DEyvm669.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-DV_orf_V.js.map → TopicsPage-DEyvm669.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-rshjKBtm.js → UserName-BV6SKI9P.js} +2 -2
- package/dashboard/dist/assets/{UserName-rshjKBtm.js.map → UserName-BV6SKI9P.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BpNGLwbK.js → WorkflowExecutionPage-1sKoEFNC.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BpNGLwbK.js.map → WorkflowExecutionPage-1sKoEFNC.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BAXt8gv_.js → WorkflowsDashboard-YTHDZZOD.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BAXt8gv_.js.map → WorkflowsDashboard-YTHDZZOD.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-DvOyzL6y.js → WorkflowsOverview-ucXPLTtm.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-DvOyzL6y.js.map → WorkflowsOverview-ucXPLTtm.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CraijGy6.js → YamlWorkflowDetailPage-C_RTZKqZ.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-CraijGy6.js.map → YamlWorkflowDetailPage-C_RTZKqZ.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CNz3ptmj.js → YamlWorkflowsPage-Usid3w2W.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CNz3ptmj.js.map → YamlWorkflowsPage-Usid3w2W.js.map} +1 -1
- package/dashboard/dist/assets/{agents-BswSJR-t.js → agents-BTDsRK8e.js} +2 -2
- package/dashboard/dist/assets/{agents-BswSJR-t.js.map → agents-BTDsRK8e.js.map} +1 -1
- package/dashboard/dist/assets/{bots-VzlLx_GQ.js → bots-DxLrfdfr.js} +2 -2
- package/dashboard/dist/assets/{bots-VzlLx_GQ.js.map → bots-DxLrfdfr.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-B0bNlTTA.js → capabilities-DbTmeW-S.js} +2 -2
- package/dashboard/dist/assets/{capabilities-B0bNlTTA.js.map → capabilities-DbTmeW-S.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DBESTVZS.js → controlplane-CEBntAL4.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DBESTVZS.js.map → controlplane-CEBntAL4.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-CoqsCdbP.js → escalation-columns-Carqdwoh.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-CoqsCdbP.js.map → escalation-columns-Carqdwoh.js.map} +1 -1
- package/dashboard/dist/assets/{index-DUfdCp8e.js → index-B2hz0pUh.js} +2 -2
- package/dashboard/dist/assets/{index-DUfdCp8e.js.map → index-B2hz0pUh.js.map} +1 -1
- package/dashboard/dist/assets/{index-DJS-hvDt.js → index-B9m7fA3M.js} +2 -2
- package/dashboard/dist/assets/{index-DJS-hvDt.js.map → index-B9m7fA3M.js.map} +1 -1
- package/dashboard/dist/assets/{index-C_lA7ghl.js → index-BhapT-Vl.js} +2 -2
- package/dashboard/dist/assets/{index-C_lA7ghl.js.map → index-BhapT-Vl.js.map} +1 -1
- package/dashboard/dist/assets/{index-DsDFZzqr.js → index-Bqm4zu46.js} +2 -2
- package/dashboard/dist/assets/{index-DsDFZzqr.js.map → index-Bqm4zu46.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cd7jZylO.js → index-C0hSttF5.js} +2 -2
- package/dashboard/dist/assets/{index-Cd7jZylO.js.map → index-C0hSttF5.js.map} +1 -1
- package/dashboard/dist/assets/{index-ByUjwu37.js → index-CDkg6iOE.js} +2 -2
- package/dashboard/dist/assets/{index-ByUjwu37.js.map → index-CDkg6iOE.js.map} +1 -1
- package/dashboard/dist/assets/{index-Ci4lxPwS.js → index-CVBBkW8V.js} +2 -2
- package/dashboard/dist/assets/{index-Ci4lxPwS.js.map → index-CVBBkW8V.js.map} +1 -1
- package/dashboard/dist/assets/{index-DYDcjn-b.js → index-CgIBjZta.js} +2 -2
- package/dashboard/dist/assets/{index-DYDcjn-b.js.map → index-CgIBjZta.js.map} +1 -1
- package/dashboard/dist/assets/{index-Cqrp5B5S.js → index-DBXm49S6.js} +25 -25
- package/dashboard/dist/assets/index-DBXm49S6.js.map +1 -0
- package/dashboard/dist/assets/{index-BBXmIWKx.js → index-De8iV1y2.js} +2 -2
- package/dashboard/dist/assets/{index-BBXmIWKx.js.map → index-De8iV1y2.js.map} +1 -1
- package/dashboard/dist/assets/{index-D8ljRGIb.js → index-DsgjFRvA.js} +2 -2
- package/dashboard/dist/assets/{index-D8ljRGIb.js.map → index-DsgjFRvA.js.map} +1 -1
- package/dashboard/dist/assets/{index-BLzwfbZV.js → index-kes8V4Xw.js} +2 -2
- package/dashboard/dist/assets/{index-BLzwfbZV.js.map → index-kes8V4Xw.js.map} +1 -1
- package/dashboard/dist/assets/{index-CALocCAr.js → index-nwLh3CK2.js} +2 -2
- package/dashboard/dist/assets/{index-CALocCAr.js.map → index-nwLh3CK2.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-DB2DgDa_.js → knowledge-oFYAanUp.js} +2 -2
- package/dashboard/dist/assets/{knowledge-DB2DgDa_.js.map → knowledge-oFYAanUp.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-D72yCeuf.js → mcp-C9Kw4Ow8.js} +2 -2
- package/dashboard/dist/assets/{mcp-D72yCeuf.js.map → mcp-C9Kw4Ow8.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-Cyyc_0E8.js → mcp-query-BwzpZ91Z.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-Cyyc_0E8.js.map → mcp-query-BwzpZ91Z.js.map} +1 -1
- package/dashboard/dist/assets/{personas-xMDV7yXb.js → personas-D5ehmtRb.js} +2 -2
- package/dashboard/dist/assets/{personas-xMDV7yXb.js.map → personas-D5ehmtRb.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-mlxfmi6m.js → pipelines-xgPKGEdD.js} +2 -2
- package/dashboard/dist/assets/{pipelines-mlxfmi6m.js.map → pipelines-xgPKGEdD.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CxgOp_9H.js → tasks-CLyrl-MU.js} +2 -2
- package/dashboard/dist/assets/{tasks-CxgOp_9H.js.map → tasks-CLyrl-MU.js.map} +1 -1
- package/dashboard/dist/assets/{topics-CFb_L0Vs.js → topics-B_gO7CQ0.js} +2 -2
- package/dashboard/dist/assets/{topics-CFb_L0Vs.js.map → topics-B_gO7CQ0.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-nC5kH-QW.js → useEventHooks-BdWYm63U.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-nC5kH-QW.js.map → useEventHooks-BdWYm63U.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DQeDgRFR.js → useNamespace-C238M4Qn.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DQeDgRFR.js.map → useNamespace-C238M4Qn.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BuGC3oBE.js → useYamlActivityEvents-B2ryEK4S.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BuGC3oBE.js.map → useYamlActivityEvents-B2ryEK4S.js.map} +1 -1
- package/dashboard/dist/assets/{users-BZUTtM_6.js → users-BFaTe6Mt.js} +2 -2
- package/dashboard/dist/assets/{users-BZUTtM_6.js.map → users-BFaTe6Mt.js.map} +1 -1
- package/dashboard/dist/assets/{workflows-DWhaZWVK.js → workflows-DXz7tZxp.js} +2 -2
- package/dashboard/dist/assets/{workflows-DWhaZWVK.js.map → workflows-DXz7tZxp.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-C1TeDIIk.js → yaml-workflows-u3xuRAnS.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-C1TeDIIk.js.map → yaml-workflows-u3xuRAnS.js.map} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/docs/code-owned-configuration.md +131 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/index-Cqrp5B5S.js.map +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LTRoleConfig } from '../../types/startup';
|
|
2
|
+
export type RoleApplyOutcome = 'applied' | 'unchanged' | 'db-owned';
|
|
3
|
+
/** Recorded on schema snapshots written by the startup apply. */
|
|
4
|
+
export declare const STARTUP_CHANGE_SUMMARY = "startup apply (code)";
|
|
5
|
+
/**
|
|
6
|
+
* Roles carrying real configuration (title or form schema) — the candidate
|
|
7
|
+
* set for the startup orphan report. Bare FK-ensured rows are excluded.
|
|
8
|
+
*/
|
|
9
|
+
export declare function listConfiguredRoles(): Promise<string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Register one declared role at startup.
|
|
12
|
+
*
|
|
13
|
+
* The role is created if missing. Under code ownership its declared fields
|
|
14
|
+
* are compared against the stored row and written through the versioned
|
|
15
|
+
* PATCH path when they differ — a changed form/metadata schema advances the
|
|
16
|
+
* role's schema version and snapshots the pair; an unchanged declaration is
|
|
17
|
+
* a no-op. Under db ownership the metadata is written exactly once (at
|
|
18
|
+
* creation); afterwards the DB owns the row and drift is warn-logged only.
|
|
19
|
+
* Escalation targets use replace semantics when declared.
|
|
20
|
+
*/
|
|
21
|
+
export declare function applyRoleConfig(cfg: LTRoleConfig, codeOwned: boolean): Promise<RoleApplyOutcome>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.STARTUP_CHANGE_SUMMARY = void 0;
|
|
4
|
+
exports.listConfiguredRoles = listConfiguredRoles;
|
|
5
|
+
exports.applyRoleConfig = applyRoleConfig;
|
|
6
|
+
const node_util_1 = require("node:util");
|
|
7
|
+
const db_1 = require("../../lib/db");
|
|
8
|
+
const logger_1 = require("../../lib/logger");
|
|
9
|
+
const index_1 = require("./index");
|
|
10
|
+
const sql_1 = require("./sql");
|
|
11
|
+
/** Recorded on schema snapshots written by the startup apply. */
|
|
12
|
+
exports.STARTUP_CHANGE_SUMMARY = 'startup apply (code)';
|
|
13
|
+
/** Metadata fields shared 1:1 between LTRoleConfig and UpdateRoleInput. */
|
|
14
|
+
const METADATA_FIELDS = [
|
|
15
|
+
'title', 'description', 'form_schema', 'metadata_schema', 'list_schema',
|
|
16
|
+
'properties', 'ops_visible', 'ops_home_default', 'parent_role',
|
|
17
|
+
'upstream_roles', 'default_pins', 'enforce_schema', 'sla_minutes',
|
|
18
|
+
'target_per_hour', 'worker_count', 'priority_threshold_minutes',
|
|
19
|
+
'priority_facet', 'entity_facet', 'entity_state_source',
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Compare one declared field against the stored row. jsonb round-trips lose
|
|
23
|
+
* key order, so structured values must be compared as parsed values — never
|
|
24
|
+
* by string. Arrays compare order-insensitively (sorted).
|
|
25
|
+
*/
|
|
26
|
+
function fieldDiffers(field, declared, row) {
|
|
27
|
+
const stored = row[field];
|
|
28
|
+
if (Array.isArray(declared)) {
|
|
29
|
+
const a = [...declared].sort();
|
|
30
|
+
const b = Array.isArray(stored) ? [...stored].sort() : [];
|
|
31
|
+
return !(0, node_util_1.isDeepStrictEqual)(a, b);
|
|
32
|
+
}
|
|
33
|
+
if (declared !== null && typeof declared === 'object') {
|
|
34
|
+
return !(0, node_util_1.isDeepStrictEqual)(declared, stored ?? null);
|
|
35
|
+
}
|
|
36
|
+
// Numeric columns round-trip as strings from the driver — compare as numbers
|
|
37
|
+
// or every declared dial would read as changed on every boot.
|
|
38
|
+
if (typeof declared === 'number') {
|
|
39
|
+
return stored == null || Number(stored) !== declared;
|
|
40
|
+
}
|
|
41
|
+
return declared !== (stored ?? undefined);
|
|
42
|
+
}
|
|
43
|
+
/** The declared fields that differ from the stored row (PATCH-shaped). */
|
|
44
|
+
function diffDeclaredFields(cfg, row) {
|
|
45
|
+
const changed = {};
|
|
46
|
+
for (const field of METADATA_FIELDS) {
|
|
47
|
+
const declared = cfg[field];
|
|
48
|
+
if (declared === undefined)
|
|
49
|
+
continue;
|
|
50
|
+
if (fieldDiffers(field, declared, row)) {
|
|
51
|
+
changed[field] = declared;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return changed;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Roles carrying real configuration (title or form schema) — the candidate
|
|
58
|
+
* set for the startup orphan report. Bare FK-ensured rows are excluded.
|
|
59
|
+
*/
|
|
60
|
+
async function listConfiguredRoles() {
|
|
61
|
+
const pool = (0, db_1.getPool)();
|
|
62
|
+
const { rows } = await pool.query(sql_1.LIST_CONFIGURED_ROLES);
|
|
63
|
+
return rows.map((r) => r.role);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Register one declared role at startup.
|
|
67
|
+
*
|
|
68
|
+
* The role is created if missing. Under code ownership its declared fields
|
|
69
|
+
* are compared against the stored row and written through the versioned
|
|
70
|
+
* PATCH path when they differ — a changed form/metadata schema advances the
|
|
71
|
+
* role's schema version and snapshots the pair; an unchanged declaration is
|
|
72
|
+
* a no-op. Under db ownership the metadata is written exactly once (at
|
|
73
|
+
* creation); afterwards the DB owns the row and drift is warn-logged only.
|
|
74
|
+
* Escalation targets use replace semantics when declared.
|
|
75
|
+
*/
|
|
76
|
+
async function applyRoleConfig(cfg, codeOwned) {
|
|
77
|
+
const created = await (0, index_1.createRole)(cfg.role);
|
|
78
|
+
const pool = (0, db_1.getPool)();
|
|
79
|
+
const { rows } = await pool.query(sql_1.GET_ROLE_ROW, [cfg.role]);
|
|
80
|
+
const row = rows[0];
|
|
81
|
+
const changed = diffDeclaredFields(cfg, row);
|
|
82
|
+
const changedFields = Object.keys(changed);
|
|
83
|
+
const declaredTargets = cfg.escalation_targets != null ? [...cfg.escalation_targets].sort() : null;
|
|
84
|
+
const storedTargets = declaredTargets != null ? await (0, index_1.getEscalationTargets)(cfg.role) : null;
|
|
85
|
+
const targetsDiffer = declaredTargets != null && !(0, node_util_1.isDeepStrictEqual)(declaredTargets, [...storedTargets].sort());
|
|
86
|
+
if (!codeOwned) {
|
|
87
|
+
if (created) {
|
|
88
|
+
// First boot for this role — write the declared metadata once. From
|
|
89
|
+
// here the DB owns the row (the dependents' "only if unconfigured"
|
|
90
|
+
// guard, moved into core).
|
|
91
|
+
if (changedFields.length > 0) {
|
|
92
|
+
await (0, index_1.updateRoleMetadata)(cfg.role, changed);
|
|
93
|
+
}
|
|
94
|
+
if (targetsDiffer)
|
|
95
|
+
await (0, index_1.replaceEscalationTargets)(cfg.role, declaredTargets);
|
|
96
|
+
return 'applied';
|
|
97
|
+
}
|
|
98
|
+
if (changedFields.length > 0 || targetsDiffer) {
|
|
99
|
+
const drifts = [...changedFields, ...(targetsDiffer ? ['escalation_targets'] : [])];
|
|
100
|
+
logger_1.loggerRegistry.warn(`[long-tail] config drift: role ${cfg.role} — ${drifts.join(', ')} differ between code and DB`);
|
|
101
|
+
}
|
|
102
|
+
return 'db-owned';
|
|
103
|
+
}
|
|
104
|
+
if (changedFields.length === 0 && !targetsDiffer)
|
|
105
|
+
return 'unchanged';
|
|
106
|
+
if (changedFields.length > 0) {
|
|
107
|
+
await (0, index_1.updateRoleMetadata)(cfg.role, { ...changed, change_summary: exports.STARTUP_CHANGE_SUMMARY });
|
|
108
|
+
}
|
|
109
|
+
if (targetsDiffer) {
|
|
110
|
+
await (0, index_1.replaceEscalationTargets)(cfg.role, declaredTargets);
|
|
111
|
+
}
|
|
112
|
+
return 'applied';
|
|
113
|
+
}
|
|
@@ -14,6 +14,14 @@ export declare const DELETE_ESCALATION_CHAINS_BY_SOURCE = "\n DELETE FROM lt_co
|
|
|
14
14
|
export declare const CHECK_ESCALATION_CHAIN_EXISTS = "\n SELECT 1\n FROM lt_config_role_escalations\n WHERE source_role = $1 AND target_role = $2";
|
|
15
15
|
export declare const ENSURE_ROLE_EXISTS = "\n INSERT INTO lt_roles (role) VALUES ($1)\n ON CONFLICT DO NOTHING";
|
|
16
16
|
export declare const LIST_ROLES = "\n SELECT role FROM lt_roles ORDER BY role";
|
|
17
|
+
/**
|
|
18
|
+
* Roles carrying real configuration (a title or a form schema). Bare FK rows
|
|
19
|
+
* and membership-only roles are excluded — the startup orphan report uses
|
|
20
|
+
* this so auto-ensured rows never read as drift.
|
|
21
|
+
*/
|
|
22
|
+
export declare const LIST_CONFIGURED_ROLES = "\n SELECT role FROM lt_roles\n WHERE title IS NOT NULL OR form_schema IS NOT NULL\n ORDER BY role";
|
|
23
|
+
/** One role's full metadata row (plus upstream inputs) for startup diffing. */
|
|
24
|
+
export declare const GET_ROLE_ROW = "\n SELECT\n r.role, r.title, r.description, r.form_schema, r.metadata_schema,\n r.properties, r.ops_visible, r.ops_home_default, r.parent_role,\n r.sla_minutes, r.target_per_hour, r.worker_count,\n r.priority_threshold_minutes, r.priority_facet,\n r.entity_facet, r.entity_state_source,\n r.list_schema, r.default_pins, r.enforce_schema,\n r.current_schema_version, r.current_list_schema_version,\n COALESCE((SELECT array_agg(u.upstream_role ORDER BY u.upstream_role)\n FROM lt_role_upstreams u WHERE u.role = r.role), '{}') AS upstream_roles\n FROM lt_roles r\n WHERE r.role = $1";
|
|
17
25
|
export declare const DELETE_ROLE = "\n DELETE FROM lt_roles WHERE role = $1";
|
|
18
26
|
/**
|
|
19
27
|
* PATCH semantics in ONE atomic statement: each column has a boolean
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// ─── Escalation chain queries ───────────────────────────────────────────────
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.COUNT_ACTIVE_ESCALATION_REFS = exports.COUNT_WORKFLOW_REFS = exports.COUNT_CHAIN_REFS = exports.COUNT_USER_ROLE_REFS = exports.LIST_ROLES_WITH_DETAILS = exports.GET_ROLE_LIST_SCHEMA_CURRENT = exports.GET_ROLE_LIST_SCHEMA_VERSION = exports.LIST_ROLE_LIST_SCHEMA_VERSIONS = exports.GET_ROLE_SCHEMA_CURRENT = exports.GET_ROLE_SCHEMA_VERSION = exports.LIST_ROLE_SCHEMA_VERSIONS = exports.GET_ROLE_UPSTREAMS = exports.GET_ROLE_PROPERTIES = exports.GET_ROLE_METADATA_SCHEMA = exports.LIST_ENFORCING_ROLES = exports.GET_ROLE_FORM_SCHEMA = exports.UPDATE_ROLE_METADATA = exports.DELETE_ROLE = exports.LIST_ROLES = exports.ENSURE_ROLE_EXISTS = exports.CHECK_ESCALATION_CHAIN_EXISTS = exports.DELETE_ESCALATION_CHAINS_BY_SOURCE = exports.DELETE_ESCALATION_CHAIN = exports.ADD_ESCALATION_CHAIN = exports.INSERT_ESCALATION_CHAIN = exports.GET_ALL_ESCALATION_CHAINS = exports.GET_ESCALATION_TARGETS = void 0;
|
|
4
|
+
exports.COUNT_ACTIVE_ESCALATION_REFS = exports.COUNT_WORKFLOW_REFS = exports.COUNT_CHAIN_REFS = exports.COUNT_USER_ROLE_REFS = exports.LIST_ROLES_WITH_DETAILS = exports.GET_ROLE_LIST_SCHEMA_CURRENT = exports.GET_ROLE_LIST_SCHEMA_VERSION = exports.LIST_ROLE_LIST_SCHEMA_VERSIONS = exports.GET_ROLE_SCHEMA_CURRENT = exports.GET_ROLE_SCHEMA_VERSION = exports.LIST_ROLE_SCHEMA_VERSIONS = exports.GET_ROLE_UPSTREAMS = exports.GET_ROLE_PROPERTIES = exports.GET_ROLE_METADATA_SCHEMA = exports.LIST_ENFORCING_ROLES = exports.GET_ROLE_FORM_SCHEMA = exports.UPDATE_ROLE_METADATA = exports.DELETE_ROLE = exports.GET_ROLE_ROW = exports.LIST_CONFIGURED_ROLES = exports.LIST_ROLES = exports.ENSURE_ROLE_EXISTS = exports.CHECK_ESCALATION_CHAIN_EXISTS = exports.DELETE_ESCALATION_CHAINS_BY_SOURCE = exports.DELETE_ESCALATION_CHAIN = exports.ADD_ESCALATION_CHAIN = exports.INSERT_ESCALATION_CHAIN = exports.GET_ALL_ESCALATION_CHAINS = exports.GET_ESCALATION_TARGETS = void 0;
|
|
5
5
|
exports.GET_ESCALATION_TARGETS = `
|
|
6
6
|
SELECT target_role
|
|
7
7
|
FROM lt_config_role_escalations
|
|
@@ -47,6 +47,29 @@ exports.ENSURE_ROLE_EXISTS = `
|
|
|
47
47
|
ON CONFLICT DO NOTHING`;
|
|
48
48
|
exports.LIST_ROLES = `
|
|
49
49
|
SELECT role FROM lt_roles ORDER BY role`;
|
|
50
|
+
/**
|
|
51
|
+
* Roles carrying real configuration (a title or a form schema). Bare FK rows
|
|
52
|
+
* and membership-only roles are excluded — the startup orphan report uses
|
|
53
|
+
* this so auto-ensured rows never read as drift.
|
|
54
|
+
*/
|
|
55
|
+
exports.LIST_CONFIGURED_ROLES = `
|
|
56
|
+
SELECT role FROM lt_roles
|
|
57
|
+
WHERE title IS NOT NULL OR form_schema IS NOT NULL
|
|
58
|
+
ORDER BY role`;
|
|
59
|
+
/** One role's full metadata row (plus upstream inputs) for startup diffing. */
|
|
60
|
+
exports.GET_ROLE_ROW = `
|
|
61
|
+
SELECT
|
|
62
|
+
r.role, r.title, r.description, r.form_schema, r.metadata_schema,
|
|
63
|
+
r.properties, r.ops_visible, r.ops_home_default, r.parent_role,
|
|
64
|
+
r.sla_minutes, r.target_per_hour, r.worker_count,
|
|
65
|
+
r.priority_threshold_minutes, r.priority_facet,
|
|
66
|
+
r.entity_facet, r.entity_state_source,
|
|
67
|
+
r.list_schema, r.default_pins, r.enforce_schema,
|
|
68
|
+
r.current_schema_version, r.current_list_schema_version,
|
|
69
|
+
COALESCE((SELECT array_agg(u.upstream_role ORDER BY u.upstream_role)
|
|
70
|
+
FROM lt_role_upstreams u WHERE u.role = r.role), '{}') AS upstream_roles
|
|
71
|
+
FROM lt_roles r
|
|
72
|
+
WHERE r.role = $1`;
|
|
50
73
|
exports.DELETE_ROLE = `
|
|
51
74
|
DELETE FROM lt_roles WHERE role = $1`;
|
|
52
75
|
/**
|
|
@@ -20,6 +20,8 @@ export interface TopicSubscriber {
|
|
|
20
20
|
topic: string;
|
|
21
21
|
reaction_type: string;
|
|
22
22
|
}
|
|
23
|
+
/** Config-declared topic names — the startup orphan report's candidate set. */
|
|
24
|
+
export declare function listConfigTopicNames(): Promise<string[]>;
|
|
23
25
|
export declare function listTopics(filters?: {
|
|
24
26
|
category?: string;
|
|
25
27
|
search?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listConfigTopicNames = listConfigTopicNames;
|
|
3
4
|
exports.listTopics = listTopics;
|
|
4
5
|
exports.getTopic = getTopic;
|
|
5
6
|
exports.createTopic = createTopic;
|
|
@@ -10,6 +11,12 @@ exports.seedTopic = seedTopic;
|
|
|
10
11
|
exports.resetTopic = resetTopic;
|
|
11
12
|
const db_1 = require("../../lib/db");
|
|
12
13
|
const sql_1 = require("./sql");
|
|
14
|
+
/** Config-declared topic names — the startup orphan report's candidate set. */
|
|
15
|
+
async function listConfigTopicNames() {
|
|
16
|
+
const pool = (0, db_1.getPool)();
|
|
17
|
+
const { rows } = await pool.query(sql_1.LIST_CONFIG_TOPIC_NAMES);
|
|
18
|
+
return rows.map((r) => r.topic);
|
|
19
|
+
}
|
|
13
20
|
async function listTopics(filters = {}) {
|
|
14
21
|
const pool = (0, db_1.getPool)();
|
|
15
22
|
const limit = filters.limit ?? 50;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const LIST_TOPICS = "\n SELECT t.*,\n COALESCE(s.sub_count, 0)::int AS subscriber_count\n FROM lt_topic_catalog t\n LEFT JOIN LATERAL (\n SELECT COUNT(*)::int AS sub_count\n FROM lt_agent_subscriptions\n WHERE enabled = true\n AND (\n topic = t.topic\n OR t.topic LIKE REPLACE(REPLACE(topic, '*', '%'), '>', '%')\n )\n ) s ON true\n WHERE ($1::text IS NULL OR t.category = $1)\n AND ($2::text IS NULL OR t.topic ILIKE '%' || $2 || '%' OR t.description ILIKE '%' || $2 || '%')\n ORDER BY t.category, t.topic\n LIMIT $3 OFFSET $4\n";
|
|
2
2
|
export declare const COUNT_TOPICS = "\n SELECT COUNT(*)::int AS total FROM lt_topic_catalog\n WHERE ($1::text IS NULL OR category = $1)\n AND ($2::text IS NULL OR topic ILIKE '%' || $2 || '%' OR description ILIKE '%' || $2 || '%')\n";
|
|
3
|
+
/** Config-declared topic names — the startup orphan report's candidate set. */
|
|
4
|
+
export declare const LIST_CONFIG_TOPIC_NAMES = "\n SELECT topic FROM lt_topic_catalog WHERE source = 'config' ORDER BY topic\n";
|
|
3
5
|
export declare const GET_TOPIC = "\n SELECT * FROM lt_topic_catalog WHERE topic = $1\n";
|
|
4
6
|
export declare const INSERT_TOPIC = "\n INSERT INTO lt_topic_catalog\n (topic, description, category, payload_schema, example_payload, source, tags)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n RETURNING *\n";
|
|
5
7
|
export declare const UPDATE_TOPIC = "\n UPDATE lt_topic_catalog SET\n description = COALESCE($2, description),\n category = COALESCE($3, category),\n payload_schema = COALESCE($4, payload_schema),\n example_payload = COALESCE($5, example_payload),\n tags = COALESCE($6, tags)\n WHERE topic = $1\n RETURNING *\n";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LIST_SUBSCRIBERS = exports.RESET_TOPIC = exports.SEED_TOPIC = exports.UPSERT_ON_PUBLISH = exports.DELETE_TOPIC = exports.UPDATE_TOPIC = exports.INSERT_TOPIC = exports.GET_TOPIC = exports.COUNT_TOPICS = exports.LIST_TOPICS = void 0;
|
|
3
|
+
exports.LIST_SUBSCRIBERS = exports.RESET_TOPIC = exports.SEED_TOPIC = exports.UPSERT_ON_PUBLISH = exports.DELETE_TOPIC = exports.UPDATE_TOPIC = exports.INSERT_TOPIC = exports.GET_TOPIC = exports.LIST_CONFIG_TOPIC_NAMES = exports.COUNT_TOPICS = exports.LIST_TOPICS = void 0;
|
|
4
4
|
exports.LIST_TOPICS = `
|
|
5
5
|
SELECT t.*,
|
|
6
6
|
COALESCE(s.sub_count, 0)::int AS subscriber_count
|
|
@@ -24,6 +24,10 @@ exports.COUNT_TOPICS = `
|
|
|
24
24
|
WHERE ($1::text IS NULL OR category = $1)
|
|
25
25
|
AND ($2::text IS NULL OR topic ILIKE '%' || $2 || '%' OR description ILIKE '%' || $2 || '%')
|
|
26
26
|
`;
|
|
27
|
+
/** Config-declared topic names — the startup orphan report's candidate set. */
|
|
28
|
+
exports.LIST_CONFIG_TOPIC_NAMES = `
|
|
29
|
+
SELECT topic FROM lt_topic_catalog WHERE source = 'config' ORDER BY topic
|
|
30
|
+
`;
|
|
27
31
|
exports.GET_TOPIC = `
|
|
28
32
|
SELECT * FROM lt_topic_catalog WHERE topic = $1
|
|
29
33
|
`;
|
|
@@ -2,6 +2,7 @@ import type { LTTopicConfig } from '../../types';
|
|
|
2
2
|
export declare function seedSystemTopics(): Promise<void>;
|
|
3
3
|
/**
|
|
4
4
|
* Seed user-declared topics from startConfig.topics[].
|
|
5
|
-
*
|
|
5
|
+
* Ownership per entry: `reset ?? defaultReset` — code-owned topics are
|
|
6
|
+
* overwritten from config on every boot; db-owned topics are insert-if-absent.
|
|
6
7
|
*/
|
|
7
|
-
export declare function seedConfigTopics(topics: LTTopicConfig[]): Promise<void>;
|
|
8
|
+
export declare function seedConfigTopics(topics: LTTopicConfig[], defaultReset?: boolean): Promise<void>;
|
|
@@ -314,9 +314,10 @@ async function seedSystemTopics() {
|
|
|
314
314
|
}
|
|
315
315
|
/**
|
|
316
316
|
* Seed user-declared topics from startConfig.topics[].
|
|
317
|
-
*
|
|
317
|
+
* Ownership per entry: `reset ?? defaultReset` — code-owned topics are
|
|
318
|
+
* overwritten from config on every boot; db-owned topics are insert-if-absent.
|
|
318
319
|
*/
|
|
319
|
-
async function seedConfigTopics(topics) {
|
|
320
|
+
async function seedConfigTopics(topics, defaultReset = false) {
|
|
320
321
|
for (const def of topics) {
|
|
321
322
|
try {
|
|
322
323
|
const payload = {
|
|
@@ -328,7 +329,7 @@ async function seedConfigTopics(topics) {
|
|
|
328
329
|
source: 'config',
|
|
329
330
|
tags: def.tags ?? [],
|
|
330
331
|
};
|
|
331
|
-
if (def.reset) {
|
|
332
|
+
if (def.reset ?? defaultReset) {
|
|
332
333
|
await (0, index_1.resetTopic)(payload);
|
|
333
334
|
logger_1.loggerRegistry.info(`[long-tail] topic reset: ${def.topic} (config)`);
|
|
334
335
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { CreateUserInput, UpdateUserInput, VALID_ROLE_TYPES } from './types';
|
|
2
2
|
export { createUser, getUser, getUserByExternalId, getUserByEmail, getUserByMetadataValue, updateUser, deleteUser, listUsers, } from './crud';
|
|
3
|
-
export { isValidRoleType, addUserRole, removeUserRole, getUserRoles, hasRole, hasRoleType, } from './roles';
|
|
3
|
+
export { isValidRoleType, addUserRole, grantRoleIfAbsent, removeUserRole, getUserRoles, hasRole, hasRoleType, } from './roles';
|
|
4
4
|
export { isSuperAdmin, isGroupAdmin, canManageRole, hasGlobalEscalationAccess, hasRolesAsAdmin, getRoleScope, getRoleWriteScope } from './rbac';
|
|
5
5
|
export { READ_SCOPES, WRITE_SCOPES, DEFAULT_READ_SCOPE, DEFAULT_WRITE_SCOPE, isValidReadScope, isValidWriteScope, isValidScopePair, effectiveScope, } from './scope';
|
|
6
6
|
export { verifyPassword } from './auth';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PREFERENCES_MAX_BYTES = exports.patchPreferences = exports.getPreferences = exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.updateUser = exports.getUserByMetadataValue = exports.getUserByEmail = exports.getUserByExternalId = exports.getUser = exports.createUser = exports.VALID_ROLE_TYPES = void 0;
|
|
3
|
+
exports.PREFERENCES_MAX_BYTES = exports.patchPreferences = exports.getPreferences = exports.seedAdmin = exports.verifyPassword = exports.effectiveScope = exports.isValidScopePair = exports.isValidWriteScope = exports.isValidReadScope = exports.DEFAULT_WRITE_SCOPE = exports.DEFAULT_READ_SCOPE = exports.WRITE_SCOPES = exports.READ_SCOPES = exports.getRoleWriteScope = exports.getRoleScope = exports.hasRolesAsAdmin = exports.hasGlobalEscalationAccess = exports.canManageRole = exports.isGroupAdmin = exports.isSuperAdmin = exports.hasRoleType = exports.hasRole = exports.getUserRoles = exports.removeUserRole = exports.grantRoleIfAbsent = exports.addUserRole = exports.isValidRoleType = exports.listUsers = exports.deleteUser = exports.updateUser = exports.getUserByMetadataValue = exports.getUserByEmail = exports.getUserByExternalId = exports.getUser = exports.createUser = exports.VALID_ROLE_TYPES = void 0;
|
|
4
4
|
var types_1 = require("./types");
|
|
5
5
|
Object.defineProperty(exports, "VALID_ROLE_TYPES", { enumerable: true, get: function () { return types_1.VALID_ROLE_TYPES; } });
|
|
6
6
|
var crud_1 = require("./crud");
|
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "listUsers", { enumerable: true, get: function ()
|
|
|
15
15
|
var roles_1 = require("./roles");
|
|
16
16
|
Object.defineProperty(exports, "isValidRoleType", { enumerable: true, get: function () { return roles_1.isValidRoleType; } });
|
|
17
17
|
Object.defineProperty(exports, "addUserRole", { enumerable: true, get: function () { return roles_1.addUserRole; } });
|
|
18
|
+
Object.defineProperty(exports, "grantRoleIfAbsent", { enumerable: true, get: function () { return roles_1.grantRoleIfAbsent; } });
|
|
18
19
|
Object.defineProperty(exports, "removeUserRole", { enumerable: true, get: function () { return roles_1.removeUserRole; } });
|
|
19
20
|
Object.defineProperty(exports, "getUserRoles", { enumerable: true, get: function () { return roles_1.getUserRoles; } });
|
|
20
21
|
Object.defineProperty(exports, "hasRole", { enumerable: true, get: function () { return roles_1.hasRole; } });
|
|
@@ -6,6 +6,14 @@ export interface RoleScopeInput {
|
|
|
6
6
|
write_scope?: LTWriteScope;
|
|
7
7
|
}
|
|
8
8
|
export declare function addUserRole(userId: string, role: string, type: LTRoleType, scope?: RoleScopeInput): Promise<LTUserRole>;
|
|
9
|
+
/**
|
|
10
|
+
* Grant a role ONLY when the user does not already hold it — the scope-safe
|
|
11
|
+
* add for sync paths (SSO provisioning, claim-time provisioning). An existing
|
|
12
|
+
* grant is never touched: identity sync adds missing memberships, it never
|
|
13
|
+
* mutates the type/scope/provenance an admin set. Returns the inserted row, or
|
|
14
|
+
* null when the membership already existed.
|
|
15
|
+
*/
|
|
16
|
+
export declare function grantRoleIfAbsent(userId: string, role: string, type: LTRoleType, scope?: RoleScopeInput): Promise<LTUserRole | null>;
|
|
9
17
|
export declare function removeUserRole(userId: string, role: string): Promise<boolean>;
|
|
10
18
|
export declare function getUserRoles(userId: string): Promise<LTUserRole[]>;
|
|
11
19
|
export declare function hasRole(userId: string, role: string): Promise<boolean>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isValidRoleType = isValidRoleType;
|
|
4
4
|
exports.addUserRole = addUserRole;
|
|
5
|
+
exports.grantRoleIfAbsent = grantRoleIfAbsent;
|
|
5
6
|
exports.removeUserRole = removeUserRole;
|
|
6
7
|
exports.getUserRoles = getUserRoles;
|
|
7
8
|
exports.hasRole = hasRole;
|
|
@@ -36,6 +37,34 @@ async function addUserRole(userId, role, type, scope) {
|
|
|
36
37
|
client.release();
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Grant a role ONLY when the user does not already hold it — the scope-safe
|
|
42
|
+
* add for sync paths (SSO provisioning, claim-time provisioning). An existing
|
|
43
|
+
* grant is never touched: identity sync adds missing memberships, it never
|
|
44
|
+
* mutates the type/scope/provenance an admin set. Returns the inserted row, or
|
|
45
|
+
* null when the membership already existed.
|
|
46
|
+
*/
|
|
47
|
+
async function grantRoleIfAbsent(userId, role, type, scope) {
|
|
48
|
+
const eff = (0, scope_1.effectiveScope)(type, scope?.read_scope ?? scope_1.DEFAULT_READ_SCOPE, scope?.write_scope ?? scope_1.DEFAULT_WRITE_SCOPE);
|
|
49
|
+
const pool = (0, db_1.getPool)();
|
|
50
|
+
// Same ensure-role + insert transaction as addUserRole: the FK target and the
|
|
51
|
+
// assignment commit together.
|
|
52
|
+
const client = await pool.connect();
|
|
53
|
+
try {
|
|
54
|
+
await client.query('BEGIN');
|
|
55
|
+
await client.query(sql_1.ENSURE_ROLE_EXISTS, [role]);
|
|
56
|
+
const { rows } = await client.query(sql_1.INSERT_USER_ROLE_IF_ABSENT, [userId, role, type, eff.read, eff.write]);
|
|
57
|
+
await client.query('COMMIT');
|
|
58
|
+
return rows[0] ?? null;
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
await client.query('ROLLBACK');
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
client.release();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
39
68
|
async function removeUserRole(userId, role) {
|
|
40
69
|
const pool = (0, db_1.getPool)();
|
|
41
70
|
const { rowCount } = await pool.query(sql_1.DELETE_USER_ROLE, [userId, role]);
|
|
@@ -37,6 +37,12 @@ export declare const GET_ROLES_BY_USER_IDS = "SELECT r.user_id, r.role, r.type,
|
|
|
37
37
|
* A direct grant takes the row over: granted_by_persona resets to NULL, so a
|
|
38
38
|
* later persona unassign can never remove a membership an admin set by hand. */
|
|
39
39
|
export declare const UPSERT_USER_ROLE = "INSERT INTO lt_user_roles (user_id, role, type, read_scope, write_scope) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (user_id, role) DO UPDATE SET\n type = EXCLUDED.type,\n read_scope = EXCLUDED.read_scope,\n write_scope = EXCLUDED.write_scope,\n granted_by_persona = NULL\n RETURNING role, type, read_scope, write_scope, created_at";
|
|
40
|
+
/** Insert a user–role assignment ONLY when absent. The scope-safe grant for
|
|
41
|
+
* sync paths (SSO, claim-time provisioning): an existing row — whatever its
|
|
42
|
+
* type/scope/provenance — is left untouched; zero rows return on conflict.
|
|
43
|
+
* Identity sync may add a missing membership but never mutates authorization
|
|
44
|
+
* an admin already set. */
|
|
45
|
+
export declare const INSERT_USER_ROLE_IF_ABSENT = "INSERT INTO lt_user_roles (user_id, role, type, read_scope, write_scope) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (user_id, role) DO NOTHING\n RETURNING role, type, read_scope, write_scope, created_at";
|
|
40
46
|
export declare const DELETE_USER_ROLE = "DELETE FROM lt_user_roles WHERE user_id = $1 AND role = $2";
|
|
41
47
|
export declare const HAS_ROLE = "SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND role = $2 LIMIT 1";
|
|
42
48
|
export declare const HAS_ROLE_TYPE = "SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND type = $2 LIMIT 1";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// ─── Shared queries (used by multiple modules) ──────────────────────────────
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.VERIFY_USER_BY_ID = exports.GET_USERS_BY_METADATA_VALUE = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = void 0;
|
|
4
|
+
exports.IS_GROUP_ADMIN = exports.GET_ROLE_SCOPE = exports.HAS_ROLE_TYPE = exports.HAS_ROLE = exports.DELETE_USER_ROLE = exports.INSERT_USER_ROLE_IF_ABSENT = exports.UPSERT_USER_ROLE = exports.GET_ROLES_BY_USER_IDS = exports.DELETE_USER_BY_ID = exports.GET_USER_WITH_ROLES = exports.VERIFY_USER_BY_ID = exports.GET_USERS_BY_METADATA_VALUE = exports.GET_USER_BY_ID = exports.GET_USER_BY_EMAIL = exports.CREATE_USER_WITH_ROLES = exports.GET_USER_BY_EXTERNAL_ID = exports.GET_ROLES_BY_USER_ID = exports.ENSURE_ROLE_EXISTS = void 0;
|
|
5
5
|
/** Ensure a role name exists in the lt_roles lookup table (FK target). */
|
|
6
6
|
exports.ENSURE_ROLE_EXISTS = 'INSERT INTO lt_roles (role) VALUES ($1) ON CONFLICT DO NOTHING';
|
|
7
7
|
/** Fetch roles for a single user, ordered by creation time. granted_by_persona
|
|
@@ -74,6 +74,14 @@ exports.UPSERT_USER_ROLE = `INSERT INTO lt_user_roles (user_id, role, type, read
|
|
|
74
74
|
write_scope = EXCLUDED.write_scope,
|
|
75
75
|
granted_by_persona = NULL
|
|
76
76
|
RETURNING role, type, read_scope, write_scope, created_at`;
|
|
77
|
+
/** Insert a user–role assignment ONLY when absent. The scope-safe grant for
|
|
78
|
+
* sync paths (SSO, claim-time provisioning): an existing row — whatever its
|
|
79
|
+
* type/scope/provenance — is left untouched; zero rows return on conflict.
|
|
80
|
+
* Identity sync may add a missing membership but never mutates authorization
|
|
81
|
+
* an admin already set. */
|
|
82
|
+
exports.INSERT_USER_ROLE_IF_ABSENT = `INSERT INTO lt_user_roles (user_id, role, type, read_scope, write_scope) VALUES ($1, $2, $3, $4, $5)
|
|
83
|
+
ON CONFLICT (user_id, role) DO NOTHING
|
|
84
|
+
RETURNING role, type, read_scope, write_scope, created_at`;
|
|
77
85
|
exports.DELETE_USER_ROLE = 'DELETE FROM lt_user_roles WHERE user_id = $1 AND role = $2';
|
|
78
86
|
exports.HAS_ROLE = 'SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND role = $2 LIMIT 1';
|
|
79
87
|
exports.HAS_ROLE_TYPE = 'SELECT 1 FROM lt_user_roles WHERE user_id = $1 AND type = $2 LIMIT 1';
|
|
@@ -49,13 +49,21 @@ async function ssoProvision(identity, ssoConfig) {
|
|
|
49
49
|
throw err;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Ensure all resolved roles exist on an already-provisioned user.
|
|
54
|
+
*
|
|
55
|
+
* SSO synchronizes IDENTITY, never authorization scope: a missing membership
|
|
56
|
+
* is added, an existing one is left exactly as the admin set it (type, scope,
|
|
57
|
+
* persona provenance). The has-check keeps the steady-state login read-only;
|
|
58
|
+
* `grantRoleIfAbsent` (INSERT … DO NOTHING) is the database-level guarantee
|
|
59
|
+
* for anything that races past it.
|
|
60
|
+
*/
|
|
53
61
|
async function syncExistingUser(userId, ltRoles) {
|
|
54
62
|
const currentRoles = await (0, roles_1.getUserRoles)(userId);
|
|
55
63
|
for (const lr of ltRoles) {
|
|
56
64
|
const has = currentRoles.some((r) => r.role === lr.role);
|
|
57
65
|
if (!has) {
|
|
58
|
-
await (0, roles_1.
|
|
66
|
+
await (0, roles_1.grantRoleIfAbsent)(userId, lr.role, lr.type);
|
|
59
67
|
}
|
|
60
68
|
}
|
|
61
69
|
const updatedRoles = await (0, roles_1.getUserRoles)(userId);
|
|
@@ -69,8 +77,11 @@ function resolveRoles(hostRoles, defaultRoleType, roleMap) {
|
|
|
69
77
|
const mapped = roleMap
|
|
70
78
|
? hostRoles.filter((r) => roleMap[r]).map((r) => roleMap[r])
|
|
71
79
|
: hostRoles;
|
|
80
|
+
// A configured roleMap is the complete contract: an unmapped host role means
|
|
81
|
+
// "no LT role" — never an injected default. The default membership applies
|
|
82
|
+
// only when no roleMap exists (raw host roles pass through, empty = default).
|
|
72
83
|
if (mapped.length === 0) {
|
|
73
|
-
return [{ role: defaultRoleType, type: defaultRoleType }];
|
|
84
|
+
return roleMap ? [] : [{ role: defaultRoleType, type: defaultRoleType }];
|
|
74
85
|
}
|
|
75
86
|
return mapped.map((role) => ({
|
|
76
87
|
role,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Who owns declared configuration after first boot. */
|
|
2
|
+
export type ConfigSource = 'code' | 'db';
|
|
3
|
+
/**
|
|
4
|
+
* Effective ownership for one declared entry: the per-entry `reset` flag wins
|
|
5
|
+
* in either direction; otherwise the global `configSource` decides.
|
|
6
|
+
*/
|
|
7
|
+
export declare function ownedByCode(reset: boolean | undefined, source: ConfigSource): boolean;
|
|
8
|
+
/** Outcome of one entry's startup pass. */
|
|
9
|
+
export type ApplyOutcome = 'applied' | 'unchanged' | 'db-owned';
|
|
10
|
+
/** Per-surface tally of a boot's config pass. */
|
|
11
|
+
export interface SurfaceReport {
|
|
12
|
+
applied: string[];
|
|
13
|
+
unchanged: string[];
|
|
14
|
+
dbOwned: string[];
|
|
15
|
+
/** DB rows of this surface not declared in code (reported, never deleted). */
|
|
16
|
+
orphans: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function newSurfaceReport(): SurfaceReport;
|
|
19
|
+
/** Record one entry's outcome on the surface report. */
|
|
20
|
+
export declare function recordOutcome(report: SurfaceReport, name: string, outcome: ApplyOutcome): void;
|
|
21
|
+
export declare function withConfigLock<T>(fn: () => Promise<T>): Promise<T>;
|
|
22
|
+
/**
|
|
23
|
+
* One boot line per surface. Warn level when orphans exist so operators see
|
|
24
|
+
* "declared set no longer matches the DB" without grepping.
|
|
25
|
+
*/
|
|
26
|
+
export declare function logSurfaceReport(surface: string, report: SurfaceReport): void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ownedByCode = ownedByCode;
|
|
4
|
+
exports.newSurfaceReport = newSurfaceReport;
|
|
5
|
+
exports.recordOutcome = recordOutcome;
|
|
6
|
+
exports.withConfigLock = withConfigLock;
|
|
7
|
+
exports.logSurfaceReport = logSurfaceReport;
|
|
8
|
+
const db_1 = require("../lib/db");
|
|
9
|
+
const logger_1 = require("../lib/logger");
|
|
10
|
+
/**
|
|
11
|
+
* Effective ownership for one declared entry: the per-entry `reset` flag wins
|
|
12
|
+
* in either direction; otherwise the global `configSource` decides.
|
|
13
|
+
*/
|
|
14
|
+
function ownedByCode(reset, source) {
|
|
15
|
+
return reset ?? source === 'code';
|
|
16
|
+
}
|
|
17
|
+
function newSurfaceReport() {
|
|
18
|
+
return { applied: [], unchanged: [], dbOwned: [], orphans: [] };
|
|
19
|
+
}
|
|
20
|
+
/** Record one entry's outcome on the surface report. */
|
|
21
|
+
function recordOutcome(report, name, outcome) {
|
|
22
|
+
if (outcome === 'applied')
|
|
23
|
+
report.applied.push(name);
|
|
24
|
+
else if (outcome === 'unchanged')
|
|
25
|
+
report.unchanged.push(name);
|
|
26
|
+
else
|
|
27
|
+
report.dbOwned.push(name);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Serializes multi-statement config writes (role-list replaces, escalation
|
|
31
|
+
* target replaces) across concurrently booting containers. Single-statement
|
|
32
|
+
* upserts are individually race-safe; the lock exists for the replace
|
|
33
|
+
* transactions and keeps boot reports coherent. Distinct from the migration
|
|
34
|
+
* lock so a slow migration on one container never blocks another's config
|
|
35
|
+
* pass behind two locks at once.
|
|
36
|
+
*/
|
|
37
|
+
const CONFIG_APPLY_LOCK_ID = 8675310;
|
|
38
|
+
async function withConfigLock(fn) {
|
|
39
|
+
const pool = (0, db_1.getPool)();
|
|
40
|
+
const client = await pool.connect();
|
|
41
|
+
try {
|
|
42
|
+
await client.query(`SELECT pg_advisory_lock(${CONFIG_APPLY_LOCK_ID})`);
|
|
43
|
+
return await fn();
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await client
|
|
47
|
+
.query(`SELECT pg_advisory_unlock(${CONFIG_APPLY_LOCK_ID})`)
|
|
48
|
+
.catch(() => { });
|
|
49
|
+
client.release();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* One boot line per surface. Warn level when orphans exist so operators see
|
|
54
|
+
* "declared set no longer matches the DB" without grepping.
|
|
55
|
+
*/
|
|
56
|
+
function logSurfaceReport(surface, report) {
|
|
57
|
+
const counts = `applied ${report.applied.length}, unchanged ${report.unchanged.length}, ` +
|
|
58
|
+
`db-owned ${report.dbOwned.length}`;
|
|
59
|
+
if (report.orphans.length > 0) {
|
|
60
|
+
logger_1.loggerRegistry.warn(`[long-tail] config apply (${surface}): ${counts}, orphans: [${report.orphans.join(', ')}]`);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
logger_1.loggerRegistry.info(`[long-tail] config apply (${surface}): ${counts}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
package/build/start/config.js
CHANGED
|
@@ -103,7 +103,14 @@ async function applyServerAuthConfig(startConfig) {
|
|
|
103
103
|
// SSO — store config for requireAuth fallback and /api/auth/sso exchange
|
|
104
104
|
if (startConfig.auth?.sso) {
|
|
105
105
|
const { setSSOConfig } = await Promise.resolve().then(() => __importStar(require('../modules/sso')));
|
|
106
|
-
|
|
106
|
+
const sso = { ...startConfig.auth.sso };
|
|
107
|
+
// A keepalive beat re-runs resolve + provisioning per tab; clamp runaway
|
|
108
|
+
// intervals (a 1s misconfiguration = one exchange per second per tab).
|
|
109
|
+
if (sso.keepaliveSeconds != null && sso.keepaliveSeconds > 0 && sso.keepaliveSeconds < 15) {
|
|
110
|
+
logger_1.loggerRegistry.warn(`[long-tail] sso.keepaliveSeconds ${sso.keepaliveSeconds}s clamped to 15s`);
|
|
111
|
+
sso.keepaliveSeconds = 15;
|
|
112
|
+
}
|
|
113
|
+
setSSOConfig(sso);
|
|
107
114
|
logger_1.loggerRegistry.info('[long-tail] SSO enabled — host auth will be trusted');
|
|
108
115
|
}
|
|
109
116
|
}
|