@hotmeshio/long-tail 0.23.1 → 0.23.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api/escalations/index.d.ts +1 -0
- package/build/api/escalations/index.js +4 -1
- package/build/api/escalations/list.d.ts +5 -0
- package/build/api/escalations/list.js +19 -5
- package/build/api/escalations/related.d.ts +18 -0
- package/build/api/escalations/related.js +205 -0
- package/build/api/roles.js +4 -0
- package/build/api/scan-codes/present.js +5 -1
- package/build/api/settings.d.ts +1 -1
- package/build/api/settings.js +3 -1
- package/build/modules/display.d.ts +15 -0
- package/build/modules/display.js +27 -0
- package/build/routes/escalations/index.js +3 -0
- package/build/routes/escalations/list.js +2 -0
- package/build/routes/escalations/related.d.ts +7 -0
- package/build/routes/escalations/related.js +60 -0
- package/build/scripts/consolidation-sim.d.ts +25 -0
- package/build/scripts/consolidation-sim.js +141 -0
- package/build/sdk/index.d.ts +12 -0
- package/build/sdk/index.js +2 -0
- package/build/services/escalation/grouped-list.d.ts +19 -0
- package/build/services/escalation/grouped-list.js +54 -0
- package/build/services/escalation/index.d.ts +4 -0
- package/build/services/escalation/index.js +9 -1
- package/build/services/escalation/queries.d.ts +17 -13
- package/build/services/escalation/queries.js +31 -40
- package/build/services/escalation/read-scope-sql.d.ts +13 -0
- package/build/services/escalation/read-scope-sql.js +19 -0
- package/build/services/escalation/related.d.ts +58 -0
- package/build/services/escalation/related.js +196 -0
- package/build/services/role/index.js +6 -0
- package/build/services/role/seed.js +4 -0
- package/build/services/scan-code/validate-facts.d.ts +1 -1
- package/build/services/scan-code/validate-facts.js +12 -1
- package/build/shared/form-validation/x-lt-scan.d.ts +8 -0
- package/build/shared/form-validation/x-lt-scan.js +20 -1
- package/build/shared/list-schema/index.d.ts +3 -0
- package/build/shared/list-schema/index.js +27 -0
- package/build/shared/list-schema/template.d.ts +14 -0
- package/build/shared/list-schema/template.js +85 -0
- package/build/shared/list-schema/types.d.ts +154 -0
- package/build/shared/list-schema/types.js +55 -0
- package/build/shared/list-schema/validate.d.ts +12 -0
- package/build/shared/list-schema/validate.js +204 -0
- package/build/shared/roles/segment.d.ts +22 -0
- package/build/shared/roles/segment.js +42 -0
- package/build/start/adapters.js +2 -0
- package/build/system/mcp-servers/admin/users.js +8 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/index.d.ts +2 -2
- package/build/types/index.js +2 -1
- package/build/types/scan-code/constants.d.ts +7 -0
- package/build/types/scan-code/constants.js +7 -1
- package/build/types/scan-code/response.d.ts +3 -2
- package/build/types/scan-code/rule.d.ts +6 -1
- package/build/types/startup.d.ts +8 -0
- package/dashboard/dist/assets/{AdminDashboard-DKrqLGjn.js → AdminDashboard-BPWsgMfZ.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DKrqLGjn.js.map → AdminDashboard-BPWsgMfZ.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BoQhRW6U.js → AgentConfigPage-De9imyo5.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-BoQhRW6U.js.map → AgentConfigPage-De9imyo5.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-DZhzuZmO.js → AgentDetailPage-B6o96Y5G.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-DZhzuZmO.js.map → AgentDetailPage-B6o96Y5G.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-5MynmbWX.js → AgentsPage-DMEmiK_W.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-5MynmbWX.js.map → AgentsPage-DMEmiK_W.js.map} +1 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-DeYMngwE.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-DeYMngwE.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-C3LR6Sqy.js → BotPicker-DDmpgGHZ.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-C3LR6Sqy.js.map → BotPicker-DDmpgGHZ.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-COjoOIIH.js → BulkAssignModal-BqlklomG.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-COjoOIIH.js.map → BulkAssignModal-BqlklomG.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-DOtjDTbK.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-DKxLvOfB.js.map → CapabilitiesPage-DOtjDTbK.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-Cz5sRx-r.js → CollapsibleSection-CLr8LP0V.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-Cz5sRx-r.js.map → CollapsibleSection-CLr8LP0V.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-Beq1vQtY.js → ConfirmDeleteModal-DW4DrPur.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-Beq1vQtY.js.map → ConfirmDeleteModal-DW4DrPur.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-DxX72PwV.js +2 -0
- package/dashboard/dist/assets/CountdownTimer-DxX72PwV.js.map +1 -0
- package/dashboard/dist/assets/{CredentialsPage-DhiHiPsG.js → CredentialsPage-CObc9Rs5.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-DhiHiPsG.js.map → CredentialsPage-CObc9Rs5.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-C9SkawB-.js → CronLabel-Bb8GoNY5.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-C9SkawB-.js.map → CronLabel-Bb8GoNY5.js.map} +1 -1
- package/dashboard/dist/assets/DataTable-FjFhx0SE.js +2 -0
- package/dashboard/dist/assets/DataTable-FjFhx0SE.js.map +1 -0
- package/dashboard/dist/assets/{ElapsedCell-BeK1SUDK.js → ElapsedCell-CmGhVlYl.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-BeK1SUDK.js.map → ElapsedCell-CmGhVlYl.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-BThdefKj.js → EntityTimelinePanel-B4Jwy1w3.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-BThdefKj.js.map → EntityTimelinePanel-B4Jwy1w3.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-DlDIYb-p.js → EscalationListSchemaPage-CZZbZ4Aa.js} +2 -2
- package/dashboard/dist/assets/{EscalationListSchemaPage-DlDIYb-p.js.map → EscalationListSchemaPage-CZZbZ4Aa.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-CQt-Embr.js → EscalationSchemaPage-D0ko59_S.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-CQt-Embr.js.map → EscalationSchemaPage-D0ko59_S.js.map} +1 -1
- package/dashboard/dist/assets/EscalationTimeline-BcnJEKFD.js +2 -0
- package/dashboard/dist/assets/EscalationTimeline-BcnJEKFD.js.map +1 -0
- package/dashboard/dist/assets/{EscalationTitleSelect-Dewrv8wX.js → EscalationTitleSelect-P0q5sck4.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-Dewrv8wX.js.map → EscalationTitleSelect-P0q5sck4.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-BzH-Y-5x.js → EscalationsOverview-BLPmh4AF.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-BzH-Y-5x.js.map → EscalationsOverview-BLPmh4AF.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-C97m6IZv.js → EventTable-gBzi5tIS.js} +2 -2
- package/dashboard/dist/assets/{EventTable-C97m6IZv.js.map → EventTable-gBzi5tIS.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-D-6xVHIw.js → FilterBar-BulSsWb2.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-D-6xVHIw.js.map → FilterBar-BulSsWb2.js.map} +1 -1
- package/dashboard/dist/assets/FormattedValue-BMHRrvrL.js +2 -0
- package/dashboard/dist/assets/FormattedValue-BMHRrvrL.js.map +1 -0
- package/dashboard/dist/assets/{GraphInvokePage-Bwi8EF9Y.js → GraphInvokePage--997yNRr.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-Bwi8EF9Y.js.map → GraphInvokePage--997yNRr.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-Z_Q03C0z.js → HomePage-CwXFz--v.js} +2 -2
- package/dashboard/dist/assets/{HomePage-Z_Q03C0z.js.map → HomePage-CwXFz--v.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-_jWTw5no.js → ListToolbar-Df4qZryJ.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-_jWTw5no.js.map → ListToolbar-Df4qZryJ.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CjqTuP0N.js → McpOverview-DrogIAKJ.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CjqTuP0N.js.map → McpOverview-DrogIAKJ.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-leCsje1U.js → McpQueryDetailPage-CJmvCAE6.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-leCsje1U.js.map → McpQueryDetailPage-CJmvCAE6.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-C-PyXYX4.js → McpQueryPage-lygo4Yq0.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-C-PyXYX4.js.map → McpQueryPage-lygo4Yq0.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-JDrr3uUQ.js → McpRunDetailPage-hvns2sCm.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-JDrr3uUQ.js.map → McpRunDetailPage-hvns2sCm.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DERXQLgZ.js → McpRunsPage-C2_7spTX.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DERXQLgZ.js.map → McpRunsPage-C2_7spTX.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-B2DA7n9m.js → OperationsPage-BlK8WlsY.js} +3 -3
- package/dashboard/dist/assets/OperationsPage-BlK8WlsY.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-BeWBiMGX.js +2 -0
- package/dashboard/dist/assets/OperatorDashboard-BeWBiMGX.js.map +1 -0
- package/dashboard/dist/assets/{PersonaDetailPage-ChXwJ6u5.js → PersonaDetailPage-CNHpsX_i.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-ChXwJ6u5.js.map → PersonaDetailPage-CNHpsX_i.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-BFFxncSE.js → PersonasPage-ChASEZRg.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-BFFxncSE.js.map → PersonasPage-ChASEZRg.js.map} +1 -1
- package/dashboard/dist/assets/PortalPage-D5Lk-PKF.js +2 -0
- package/dashboard/dist/assets/PortalPage-D5Lk-PKF.js.map +1 -0
- package/dashboard/dist/assets/{ProcessDetailPage-D7EYwW-j.js → ProcessDetailPage-DNgCIwRl.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-D7EYwW-j.js.map → ProcessDetailPage-DNgCIwRl.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-CakYRtnE.js → ProcessesListPage-pRjWuWlH.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-CakYRtnE.js.map → ProcessesListPage-pRjWuWlH.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js +8 -0
- package/dashboard/dist/assets/ResolverForm-CKIOAGtY.js.map +1 -0
- package/dashboard/dist/assets/{RoleDetailPage-CKbGwezP.js → RoleDetailPage-Bh_UcfYY.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-CKbGwezP.js.map → RoleDetailPage-Bh_UcfYY.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-Czu7Zku4.js → RolesPage-CK17N7zz.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-Czu7Zku4.js.map → RolesPage-CK17N7zz.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-6BLScYTX.js → RunAsSelector-BEKUP0p2.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-6BLScYTX.js.map → RunAsSelector-BEKUP0p2.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-Cv9q8Bvt.js → ScanCodesPage-Bd0Pflqx.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-Cv9q8Bvt.js.map → ScanCodesPage-Bd0Pflqx.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-BxazXYIc.js → ScanSchemeDetailPage-CnuhozmJ.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-BxazXYIc.js.map → ScanSchemeDetailPage-CnuhozmJ.js.map} +1 -1
- package/dashboard/dist/assets/ScanStationPage-CoLc-q3h.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-CoLc-q3h.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-DsdtYoXR.js → StickyPagination-COrfvkBi.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-DsdtYoXR.js.map → StickyPagination-COrfvkBi.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-CT3FQoT3.js → StreamMessageDetail-Cif2egLy.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-CT3FQoT3.js.map → StreamMessageDetail-Cif2egLy.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-C8TjkJ10.js → SwimlaneTimeline-BnZYTrAh.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-C8TjkJ10.js.map → SwimlaneTimeline-BnZYTrAh.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-DGUzdBFN.js → TaskDetailPage-DEz_dqyR.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-DGUzdBFN.js.map → TaskDetailPage-DEz_dqyR.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-BVIP6-EZ.js → TasksListPage-oEfEGj0_.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-BVIP6-EZ.js.map → TasksListPage-oEfEGj0_.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-C-rd9F9g.js → TimeAgo-Dz5TgZZZ.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-C-rd9F9g.js.map → TimeAgo-Dz5TgZZZ.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-DPbchDOI.js → TimestampCell-BUTgE244.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-DPbchDOI.js.map → TimestampCell-BUTgE244.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-DAUC8DHK.js → ToolTestPanel-BS4g6vt-.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-DAUC8DHK.js.map → ToolTestPanel-BS4g6vt-.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-70mMKBzG.js → TopicDetailPage-C_I6JIVD.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-70mMKBzG.js.map → TopicDetailPage-C_I6JIVD.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-CE3hBthn.js → TopicsPage-Cr6-wfhJ.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-CE3hBthn.js.map → TopicsPage-Cr6-wfhJ.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-BDBDA-LR.js → UserName-ZFpWMaFF.js} +2 -2
- package/dashboard/dist/assets/{UserName-BDBDA-LR.js.map → UserName-ZFpWMaFF.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BbkLZ1co.js → WorkflowExecutionPage-ByPixDZW.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BbkLZ1co.js.map → WorkflowExecutionPage-ByPixDZW.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-Bp1L7Ggz.js → WorkflowsDashboard-CWsJdMdR.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-Bp1L7Ggz.js.map → WorkflowsDashboard-CWsJdMdR.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-IeTKHAi4.js → WorkflowsOverview-Dk9gyqZN.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-IeTKHAi4.js.map → WorkflowsOverview-Dk9gyqZN.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DtKCXnKt.js → YamlWorkflowDetailPage-CHwcrsaT.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DtKCXnKt.js.map → YamlWorkflowDetailPage-CHwcrsaT.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEcZBV_3.js → YamlWorkflowsPage-B5jRX2Ph.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEcZBV_3.js.map → YamlWorkflowsPage-B5jRX2Ph.js.map} +1 -1
- package/dashboard/dist/assets/{agents-BT-sEk81.js → agents-Dd7E-27d.js} +2 -2
- package/dashboard/dist/assets/{agents-BT-sEk81.js.map → agents-Dd7E-27d.js.map} +1 -1
- package/dashboard/dist/assets/{bots-DRoAdLek.js → bots-CpaYjZTk.js} +2 -2
- package/dashboard/dist/assets/{bots-DRoAdLek.js.map → bots-CpaYjZTk.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-Bc-nJk6y.js → capabilities-CNjg_qv1.js} +2 -2
- package/dashboard/dist/assets/{capabilities-Bc-nJk6y.js.map → capabilities-CNjg_qv1.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-aXceSIRf.js → controlplane-DgmvnAtU.js} +2 -2
- package/dashboard/dist/assets/{controlplane-aXceSIRf.js.map → controlplane-DgmvnAtU.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-Uj4U9g5H.js +2 -0
- package/dashboard/dist/assets/escalation-columns-Uj4U9g5H.js.map +1 -0
- package/dashboard/dist/assets/{index-C3VTJcrp.js → index-BFASQ7_X.js} +2 -2
- package/dashboard/dist/assets/{index-C3VTJcrp.js.map → index-BFASQ7_X.js.map} +1 -1
- package/dashboard/dist/assets/{index-DH03y-UT.js → index-BT1Ms5Q5.js} +2 -2
- package/dashboard/dist/assets/{index-DH03y-UT.js.map → index-BT1Ms5Q5.js.map} +1 -1
- package/dashboard/dist/assets/{index-Djsoi8DI.js → index-BrwqtXRh.js} +2 -2
- package/dashboard/dist/assets/{index-Djsoi8DI.js.map → index-BrwqtXRh.js.map} +1 -1
- package/dashboard/dist/assets/index-BsHVgWH6.js +13 -0
- package/dashboard/dist/assets/{index-BEPKAjna.js.map → index-BsHVgWH6.js.map} +1 -1
- package/dashboard/dist/assets/index-ByBy9M3L.js +2 -0
- package/dashboard/dist/assets/{index-BCFEQEMC.js.map → index-ByBy9M3L.js.map} +1 -1
- package/dashboard/dist/assets/{index-CZyO9hRb.js → index-C_K7OlzT.js} +2 -2
- package/dashboard/dist/assets/{index-CZyO9hRb.js.map → index-C_K7OlzT.js.map} +1 -1
- package/dashboard/dist/assets/{index-Ba-s5Yb5.js → index-CnOvJz6U.js} +2 -2
- package/dashboard/dist/assets/{index-Ba-s5Yb5.js.map → index-CnOvJz6U.js.map} +1 -1
- package/dashboard/dist/assets/{index-CcgmR-7-.js → index-CtlBjl8o.js} +2 -2
- package/dashboard/dist/assets/{index-CcgmR-7-.js.map → index-CtlBjl8o.js.map} +1 -1
- package/dashboard/dist/assets/{index-DBxpyIw5.js → index-D4Dlznn9.js} +2 -2
- package/dashboard/dist/assets/{index-DBxpyIw5.js.map → index-D4Dlznn9.js.map} +1 -1
- package/dashboard/dist/assets/{index-BUYokcrl.js → index-LRYC__mE.js} +30 -30
- package/dashboard/dist/assets/index-LRYC__mE.js.map +1 -0
- package/dashboard/dist/assets/{index-DcppjzP5.css → index-MYI2_Xb3.css} +1 -1
- package/dashboard/dist/assets/index-OfO0173w.js +3 -0
- package/dashboard/dist/assets/index-OfO0173w.js.map +1 -0
- package/dashboard/dist/assets/{index-h2gX31B2.js → index-RIFT3RlO.js} +2 -2
- package/dashboard/dist/assets/{index-h2gX31B2.js.map → index-RIFT3RlO.js.map} +1 -1
- package/dashboard/dist/assets/{index-CuBGGwXf.js → index-x5z73M9N.js} +2 -2
- package/dashboard/dist/assets/{index-CuBGGwXf.js.map → index-x5z73M9N.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-BhW8V-Hq.js → knowledge-Cci_r6Kl.js} +2 -2
- package/dashboard/dist/assets/{knowledge-BhW8V-Hq.js.map → knowledge-Cci_r6Kl.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-BYfSMQzh.js → mcp-NY4iL0L-.js} +2 -2
- package/dashboard/dist/assets/{mcp-BYfSMQzh.js.map → mcp-NY4iL0L-.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-DUJoOk_q.js → mcp-query-CbvZo_I_.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-DUJoOk_q.js.map → mcp-query-CbvZo_I_.js.map} +1 -1
- package/dashboard/dist/assets/{personas-jT1O_SB4.js → personas-Fy-f7QQd.js} +2 -2
- package/dashboard/dist/assets/{personas-jT1O_SB4.js.map → personas-Fy-f7QQd.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Bp-wIaz2.js → pipelines-DKiuozxV.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Bp-wIaz2.js.map → pipelines-DKiuozxV.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-CCrvnXbz.js → tasks-CdM1Rkk9.js} +2 -2
- package/dashboard/dist/assets/{tasks-CCrvnXbz.js.map → tasks-CdM1Rkk9.js.map} +1 -1
- package/dashboard/dist/assets/{topics-Blft0I1L.js → topics-XNy2mf3n.js} +2 -2
- package/dashboard/dist/assets/{topics-Blft0I1L.js.map → topics-XNy2mf3n.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-BYqbcism.js → useDebouncedValue-CyGcU3_S.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-BYqbcism.js.map → useDebouncedValue-CyGcU3_S.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-BfxJAUgG.js → useNamespace-C2RIh_IN.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-BfxJAUgG.js.map → useNamespace-C2RIh_IN.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BukJuWpb.js → useYamlActivityEvents-CDiV5fjf.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BukJuWpb.js.map → useYamlActivityEvents-CDiV5fjf.js.map} +1 -1
- package/dashboard/dist/assets/validate-DcGWN82Y.js +2 -0
- package/dashboard/dist/assets/validate-DcGWN82Y.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-DeRWqMGk.js → yaml-workflows-CH8UrouH.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-DeRWqMGk.js.map → yaml-workflows-CH8UrouH.js.map} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/docs/api/http/escalations.md +46 -0
- package/docs/api/sdk/escalations.md +16 -0
- package/docs/code-owned-configuration.md +12 -0
- package/docs/hitl/portal.md +2 -0
- package/docs/hitl/x-lt-list-schema.md +88 -1
- package/docs/hitl/x-lt-scan.md +4 -1
- package/docs/scan-codes.md +7 -1
- package/package.json +2 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-CWMyy3IL.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-CWMyy3IL.js.map +0 -1
- package/dashboard/dist/assets/CapabilitiesPage-DKxLvOfB.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-BUBl_4mP.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-BUBl_4mP.js.map +0 -1
- package/dashboard/dist/assets/DataTable-spX1dFyb.js +0 -2
- package/dashboard/dist/assets/DataTable-spX1dFyb.js.map +0 -1
- package/dashboard/dist/assets/EscalationListView-DTIVuym4.js +0 -2
- package/dashboard/dist/assets/EscalationListView-DTIVuym4.js.map +0 -1
- package/dashboard/dist/assets/EscalationTimeline-DNKNp6pL.js +0 -2
- package/dashboard/dist/assets/EscalationTimeline-DNKNp6pL.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-B2DA7n9m.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-C8RtPv8P.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-C8RtPv8P.js.map +0 -1
- package/dashboard/dist/assets/PortalPage-Xk1zVneM.js +0 -2
- package/dashboard/dist/assets/PortalPage-Xk1zVneM.js.map +0 -1
- package/dashboard/dist/assets/ResolverForm-BwVOJUpJ.js +0 -8
- package/dashboard/dist/assets/ResolverForm-BwVOJUpJ.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-Bf09Q89t.js +0 -2
- package/dashboard/dist/assets/escalation-columns-Bf09Q89t.js.map +0 -1
- package/dashboard/dist/assets/index-BCFEQEMC.js +0 -2
- package/dashboard/dist/assets/index-BEPKAjna.js +0 -13
- package/dashboard/dist/assets/index-BUYokcrl.js.map +0 -1
- package/dashboard/dist/assets/index-D1mKf_qz.js +0 -3
- package/dashboard/dist/assets/index-D1mKf_qz.js.map +0 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Related sets for list views: a host row's items (each read through its
|
|
4
|
+
// payload or its reciprocal row) and rows in other roles that share facets
|
|
5
|
+
// with it. Every statement serves a whole page of hosts and composes the
|
|
6
|
+
// caller's read scope, so the cost is bounded by the declaration, never by
|
|
7
|
+
// the page size or the item count.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.aggregateRelatedItems = aggregateRelatedItems;
|
|
11
|
+
exports.listRelatedItems = listRelatedItems;
|
|
12
|
+
exports.aggregateRelatedQuery = aggregateRelatedQuery;
|
|
13
|
+
exports.listRelatedQueryRows = listRelatedQueryRows;
|
|
14
|
+
exports.readRelatedHosts = readRelatedHosts;
|
|
15
|
+
const db_1 = require("../../lib/db");
|
|
16
|
+
const uuid_1 = require("../../lib/uuid");
|
|
17
|
+
const escalation_1 = require("../../types/escalation");
|
|
18
|
+
const list_schema_1 = require("../../shared/list-schema");
|
|
19
|
+
const client_1 = require("./client");
|
|
20
|
+
const map_1 = require("./map");
|
|
21
|
+
const read_scope_sql_1 = require("./read-scope-sql");
|
|
22
|
+
const UUID_PATTERN = uuid_1.UUID_RE.source;
|
|
23
|
+
function foldAggregateRows(rows, hostIds, split) {
|
|
24
|
+
const out = {};
|
|
25
|
+
for (const id of hostIds)
|
|
26
|
+
out[id] = split ? { count: 0, splits: {} } : { count: 0 };
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
const agg = out[row.host_id];
|
|
29
|
+
if (!agg)
|
|
30
|
+
continue;
|
|
31
|
+
agg.count += row.n;
|
|
32
|
+
if (row.hidden) {
|
|
33
|
+
agg.hidden = (agg.hidden ?? 0) + row.n;
|
|
34
|
+
}
|
|
35
|
+
else if (split) {
|
|
36
|
+
const key = row.split ?? '';
|
|
37
|
+
agg.splits[key] = (agg.splits[key] ?? 0) + row.n;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
/** The hosts and their item entries, read under the caller's scope. */
|
|
43
|
+
function itemEntriesCte(params, scope, hostIds) {
|
|
44
|
+
const hi = params.push(hostIds);
|
|
45
|
+
const hostScope = (0, read_scope_sql_1.buildReadScopeClause)(scope, params, 'h');
|
|
46
|
+
return `hosts AS (
|
|
47
|
+
SELECT h.id, h.envelope,
|
|
48
|
+
(h.envelope ? '${escalation_1.ESCALATION_ACCUMULATE_KEYS.ITEMS}') AS acc,
|
|
49
|
+
COALESCE(h.envelope->'${escalation_1.ESCALATION_ACCUMULATE_KEYS.ITEMS}', h.envelope->'${escalation_1.ESCALATION_BATCH_KEYS.ITEMS}') AS items
|
|
50
|
+
FROM public.lt_escalations h
|
|
51
|
+
WHERE h.id = ANY($${hi}::uuid[])${hostScope ? ` AND ${hostScope}` : ''}
|
|
52
|
+
), entries AS (
|
|
53
|
+
SELECT hosts.id AS host_id, hosts.acc, hosts.envelope, e.key AS item_key, e.value AS entry,
|
|
54
|
+
CASE WHEN hosts.acc AND (e.value->>'reciprocalId') ~* '${UUID_PATTERN}'
|
|
55
|
+
THEN (e.value->>'reciprocalId')::uuid END AS rid
|
|
56
|
+
FROM hosts, jsonb_each(CASE WHEN jsonb_typeof(hosts.items) = 'object' THEN hosts.items ELSE '{}'::jsonb END) e
|
|
57
|
+
)`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Count each host's items, optionally split by `payload.<path>` or
|
|
61
|
+
* `reciprocal.metadata.<key>`. A reciprocal split counts only reciprocal rows
|
|
62
|
+
* the caller can read; the rest are reported as `hidden`. `roles` names the
|
|
63
|
+
* roles of the readable reciprocal rows, so a list can follow their changes.
|
|
64
|
+
*/
|
|
65
|
+
async function aggregateRelatedItems(opts) {
|
|
66
|
+
if (!opts.hostIds.length)
|
|
67
|
+
return { aggregates: {}, roles: [] };
|
|
68
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
69
|
+
const params = [];
|
|
70
|
+
const cte = itemEntriesCte(params, opts.scope, opts.hostIds);
|
|
71
|
+
const splitBy = opts.splitBy ?? '';
|
|
72
|
+
let splitExpr = 'NULL::text';
|
|
73
|
+
let join = '';
|
|
74
|
+
let hiddenExpr = 'false';
|
|
75
|
+
let rolesExpr = 'NULL::text[]';
|
|
76
|
+
if (splitBy.startsWith(list_schema_1.SPLIT_PATHS.PAYLOAD)) {
|
|
77
|
+
const pi = params.push(splitBy.slice(list_schema_1.SPLIT_PATHS.PAYLOAD.length).split('.'));
|
|
78
|
+
splitExpr = `(CASE WHEN en.acc THEN en.entry->'payload' ELSE en.entry END) #>> $${pi}::text[]`;
|
|
79
|
+
}
|
|
80
|
+
else if (splitBy.startsWith(list_schema_1.SPLIT_PATHS.RECIPROCAL_METADATA)) {
|
|
81
|
+
const ki = params.push(splitBy.slice(list_schema_1.SPLIT_PATHS.RECIPROCAL_METADATA.length));
|
|
82
|
+
const rScope = (0, read_scope_sql_1.buildReadScopeClause)(opts.scope, params, 'r');
|
|
83
|
+
join = `LEFT JOIN public.lt_escalations r ON r.id = en.rid${rScope ? ` AND ${rScope}` : ''}`;
|
|
84
|
+
splitExpr = `r.metadata->>$${ki}`;
|
|
85
|
+
hiddenExpr = '(en.rid IS NOT NULL AND r.id IS NULL)';
|
|
86
|
+
rolesExpr = 'array_agg(DISTINCT r.role) FILTER (WHERE r.id IS NOT NULL)';
|
|
87
|
+
}
|
|
88
|
+
const { rows } = await (0, db_1.getPool)().query(`WITH ${cte}
|
|
89
|
+
SELECT en.host_id::text AS host_id, ${splitExpr} AS split, ${hiddenExpr} AS hidden, count(*)::int AS n,
|
|
90
|
+
${rolesExpr} AS roles
|
|
91
|
+
FROM entries en ${join}
|
|
92
|
+
GROUP BY 1, 2, 3`, params);
|
|
93
|
+
const roles = new Set(rows.flatMap((row) => row.roles ?? []));
|
|
94
|
+
return { aggregates: foldAggregateRows(rows, opts.hostIds, !!splitBy), roles: [...roles].sort() };
|
|
95
|
+
}
|
|
96
|
+
/** One host's items in fill order, each with its reciprocal row when readable. */
|
|
97
|
+
async function listRelatedItems(opts) {
|
|
98
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
99
|
+
const params = [];
|
|
100
|
+
const cte = itemEntriesCte(params, opts.scope, [opts.hostId]);
|
|
101
|
+
const rScope = (0, read_scope_sql_1.buildReadScopeClause)(opts.scope, params, 'r');
|
|
102
|
+
const li = params.push(opts.limit);
|
|
103
|
+
const { rows } = await (0, db_1.getPool)().query(`WITH ${cte}
|
|
104
|
+
SELECT en.item_key, en.entry, en.acc,
|
|
105
|
+
en.envelope->'${escalation_1.ESCALATION_BATCH_KEYS.FILLED_AT}'->>en.item_key AS batch_at,
|
|
106
|
+
en.envelope->'${escalation_1.ESCALATION_BATCH_KEYS.FILLED_BY}'->>en.item_key AS batch_actor,
|
|
107
|
+
(en.rid IS NOT NULL AND r.id IS NULL) AS hidden,
|
|
108
|
+
CASE WHEN r.id IS NULL THEN NULL ELSE to_jsonb(r) END AS reciprocal,
|
|
109
|
+
count(*) OVER ()::int AS total
|
|
110
|
+
FROM entries en
|
|
111
|
+
LEFT JOIN public.lt_escalations r ON r.id = en.rid${rScope ? ` AND ${rScope}` : ''}
|
|
112
|
+
ORDER BY COALESCE(CASE WHEN en.acc THEN en.entry->>'at' END,
|
|
113
|
+
en.envelope->'${escalation_1.ESCALATION_BATCH_KEYS.FILLED_AT}'->>en.item_key) NULLS LAST, en.item_key
|
|
114
|
+
LIMIT $${li}`, params);
|
|
115
|
+
return {
|
|
116
|
+
total: rows[0]?.total ?? 0,
|
|
117
|
+
rows: rows.map((row) => {
|
|
118
|
+
const entry = row.entry ?? {};
|
|
119
|
+
const item = row.acc
|
|
120
|
+
? {
|
|
121
|
+
itemKey: row.item_key,
|
|
122
|
+
payload: entry.payload,
|
|
123
|
+
at: entry.at,
|
|
124
|
+
...(entry.actor ? { actor: entry.actor } : {}),
|
|
125
|
+
...(entry.reciprocalId ? { reciprocalId: entry.reciprocalId } : {}),
|
|
126
|
+
}
|
|
127
|
+
: {
|
|
128
|
+
itemKey: row.item_key,
|
|
129
|
+
payload: entry,
|
|
130
|
+
...(row.batch_at ? { at: row.batch_at } : {}),
|
|
131
|
+
...(row.batch_actor ? { actor: row.batch_actor } : {}),
|
|
132
|
+
};
|
|
133
|
+
return { item, escalation: row.reciprocal ? (0, map_1.toEscalationRecord)(row.reciprocal) : null };
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/** The shared FROM/WHERE of a query set: hosts unnested beside their matches. */
|
|
138
|
+
function querySetFrom(params, input) {
|
|
139
|
+
const hi = params.push(input.hosts.map((h) => h.hostId));
|
|
140
|
+
const mi = params.push(input.hosts.map((h) => JSON.stringify(h.match)));
|
|
141
|
+
const ri = params.push(input.roles);
|
|
142
|
+
const si = params.push(input.status);
|
|
143
|
+
const scope = (0, read_scope_sql_1.buildReadScopeClause)(input.scope, params, 'e');
|
|
144
|
+
return `FROM unnest($${hi}::text[], $${mi}::jsonb[]) AS h(host_id, match)
|
|
145
|
+
JOIN public.lt_escalations e ON e.metadata @> h.match
|
|
146
|
+
WHERE e.role = ANY($${ri}::text[]) AND e.status = $${si}
|
|
147
|
+
AND e.id::text <> h.host_id${scope ? ` AND ${scope}` : ''}`;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Count the rows that share each host's facets, grouped by role and an
|
|
151
|
+
* optional `metadata.<key>` split. The GIN index serves each host's match.
|
|
152
|
+
*/
|
|
153
|
+
async function aggregateRelatedQuery(input) {
|
|
154
|
+
const hostIds = input.hosts.map((h) => h.hostId);
|
|
155
|
+
if (!hostIds.length || !input.roles.length)
|
|
156
|
+
return foldAggregateRows([], hostIds, !!input.splitBy);
|
|
157
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
158
|
+
const params = [];
|
|
159
|
+
const from = querySetFrom(params, input);
|
|
160
|
+
let splitExpr = 'NULL::text';
|
|
161
|
+
if (input.splitBy === list_schema_1.SPLIT_PATHS.ROLE) {
|
|
162
|
+
splitExpr = 'e.role';
|
|
163
|
+
}
|
|
164
|
+
else if (input.splitBy?.startsWith(list_schema_1.SPLIT_PATHS.METADATA)) {
|
|
165
|
+
splitExpr = `e.metadata->>$${params.push(input.splitBy.slice(list_schema_1.SPLIT_PATHS.METADATA.length))}`;
|
|
166
|
+
}
|
|
167
|
+
const { rows } = await (0, db_1.getPool)().query(`SELECT h.host_id, ${splitExpr} AS split, count(*)::int AS n ${from} GROUP BY 1, 2`, params);
|
|
168
|
+
return foldAggregateRows(rows, hostIds, !!input.splitBy);
|
|
169
|
+
}
|
|
170
|
+
/** One host's related rows, in role order then age. */
|
|
171
|
+
async function listRelatedQueryRows(input) {
|
|
172
|
+
if (!input.hosts.length || !input.roles.length)
|
|
173
|
+
return { rows: [], total: 0 };
|
|
174
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
175
|
+
const params = [];
|
|
176
|
+
const from = querySetFrom(params, input);
|
|
177
|
+
const oi = params.push(input.roles);
|
|
178
|
+
const li = params.push(input.limit);
|
|
179
|
+
const { rows } = await (0, db_1.getPool)().query(`SELECT to_jsonb(e) AS row, count(*) OVER ()::int AS total ${from}
|
|
180
|
+
ORDER BY array_position($${oi}::text[], e.role), e.created_at
|
|
181
|
+
LIMIT $${li}`, params);
|
|
182
|
+
return {
|
|
183
|
+
total: rows[0]?.total ?? 0,
|
|
184
|
+
rows: rows.map((r) => ({ escalation: (0, map_1.toEscalationRecord)(r.row) })),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/** Host rows of one role, read under the caller's scope. */
|
|
188
|
+
async function readRelatedHosts(opts) {
|
|
189
|
+
if (!opts.ids.length)
|
|
190
|
+
return [];
|
|
191
|
+
await (0, client_1.ensureEscalationCompatView)();
|
|
192
|
+
const params = [opts.ids, opts.role];
|
|
193
|
+
const scope = (0, read_scope_sql_1.buildReadScopeClause)(opts.scope, params);
|
|
194
|
+
const { rows } = await (0, db_1.getPool)().query(`SELECT * FROM public.lt_escalations WHERE id = ANY($1::uuid[]) AND role = $2${scope ? ` AND ${scope}` : ''}`, params);
|
|
195
|
+
return rows.map((row) => (0, map_1.toEscalationRecord)(row));
|
|
196
|
+
}
|
|
@@ -19,6 +19,7 @@ exports.getRoleFormSchema = getRoleFormSchema;
|
|
|
19
19
|
exports.getRoleMetadataSchema = getRoleMetadataSchema;
|
|
20
20
|
exports.getRoleProperties = getRoleProperties;
|
|
21
21
|
exports.deleteRole = deleteRole;
|
|
22
|
+
const list_schema_1 = require("../../shared/list-schema");
|
|
22
23
|
const db_1 = require("../../lib/db");
|
|
23
24
|
const user_1 = require("../user");
|
|
24
25
|
const sql_1 = require("./sql");
|
|
@@ -128,6 +129,11 @@ async function createRole(role) {
|
|
|
128
129
|
* resets to {}). One atomic UPDATE — see UPDATE_ROLE_METADATA.
|
|
129
130
|
*/
|
|
130
131
|
async function updateRoleMetadata(role, input) {
|
|
132
|
+
if (input.list_schema != null) {
|
|
133
|
+
const listSchemaError = (0, list_schema_1.listSchemaRelationsError)(input.list_schema);
|
|
134
|
+
if (listSchemaError)
|
|
135
|
+
throw new Error(`list_schema: ${listSchemaError}`);
|
|
136
|
+
}
|
|
131
137
|
const pool = (0, db_1.getPool)();
|
|
132
138
|
const provided = (key) => input[key] !== undefined;
|
|
133
139
|
const upstreams = [...new Set(input.upstream_roles ?? [])].sort();
|
|
@@ -9,6 +9,7 @@ const logger_1 = require("../../lib/logger");
|
|
|
9
9
|
const index_1 = require("./index");
|
|
10
10
|
const sql_1 = require("./sql");
|
|
11
11
|
const badge_grant_1 = require("./badge-grant");
|
|
12
|
+
const list_schema_1 = require("../../shared/list-schema");
|
|
12
13
|
const types_1 = require("./types");
|
|
13
14
|
/** Recorded on schema snapshots written by the startup apply. */
|
|
14
15
|
exports.STARTUP_CHANGE_SUMMARY = 'startup apply (code)';
|
|
@@ -84,6 +85,9 @@ async function applyRoleConfig(cfg, codeOwned) {
|
|
|
84
85
|
const grantError = (0, badge_grant_1.badgeGrantError)(cfg.properties?.[types_1.ROLE_PROPERTY_KEYS.BADGE_GRANT]);
|
|
85
86
|
if (grantError)
|
|
86
87
|
throw new Error(`role ${cfg.role}: ${grantError}`);
|
|
88
|
+
const listSchemaError = cfg.list_schema != null ? (0, list_schema_1.listSchemaRelationsError)(cfg.list_schema) : null;
|
|
89
|
+
if (listSchemaError)
|
|
90
|
+
throw new Error(`role ${cfg.role}: list_schema: ${listSchemaError}`);
|
|
87
91
|
const created = await (0, index_1.createRole)(cfg.role);
|
|
88
92
|
const pool = (0, db_1.getPool)();
|
|
89
93
|
const { rows } = await pool.query(sql_1.GET_ROLE_ROW, [cfg.role]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ScanStep } from '../../types';
|
|
2
2
|
/** The most facts a station screen states before it reads as a data dump. */
|
|
3
3
|
export declare const SCAN_FACTS_MAX = 12;
|
|
4
|
-
/** `facts` on a present step: labeled template values the station states. */
|
|
4
|
+
/** `facts` on a present step: labeled template values the station states, optionally formatted. */
|
|
5
5
|
export declare function assertValidFacts(step: ScanStep, at: string): void;
|
|
@@ -3,9 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SCAN_FACTS_MAX = void 0;
|
|
4
4
|
exports.assertValidFacts = assertValidFacts;
|
|
5
5
|
const types_1 = require("../../types");
|
|
6
|
+
const FACT_FORMATS = new Set(Object.values(types_1.SCAN_FACT_FORMATS));
|
|
7
|
+
/** A formatted fact reads one value: a single `{bag.key}` token. */
|
|
8
|
+
const SINGLE_TOKEN = /^\{[a-z]+\.[^{}]+\}$/;
|
|
6
9
|
/** The most facts a station screen states before it reads as a data dump. */
|
|
7
10
|
exports.SCAN_FACTS_MAX = 12;
|
|
8
|
-
/** `facts` on a present step: labeled template values the station states. */
|
|
11
|
+
/** `facts` on a present step: labeled template values the station states, optionally formatted. */
|
|
9
12
|
function assertValidFacts(step, at) {
|
|
10
13
|
if (step.facts === undefined)
|
|
11
14
|
return;
|
|
@@ -20,5 +23,13 @@ function assertValidFacts(step, at) {
|
|
|
20
23
|
}
|
|
21
24
|
if (typeof fact.value !== 'string')
|
|
22
25
|
throw new Error(`${at}: facts[${i}].value must be a template string`);
|
|
26
|
+
if (fact.format === undefined)
|
|
27
|
+
return;
|
|
28
|
+
if (!FACT_FORMATS.has(fact.format)) {
|
|
29
|
+
throw new Error(`${at}: facts[${i}].format must be one of ${[...FACT_FORMATS].join(', ')}`);
|
|
30
|
+
}
|
|
31
|
+
if (!SINGLE_TOKEN.test(fact.value.trim())) {
|
|
32
|
+
throw new Error(`${at}: facts[${i}] with a format must read a single token, e.g. {item.releaseAt}`);
|
|
33
|
+
}
|
|
23
34
|
});
|
|
24
35
|
}
|
|
@@ -10,6 +10,8 @@ export interface ScanSink {
|
|
|
10
10
|
expectError: string;
|
|
11
11
|
/** Array fields: 'count' takes a value as many times as it is expected. */
|
|
12
12
|
multiplicity: 'count' | 'once';
|
|
13
|
+
/** Array fields: the instruction shown while the field is empty. */
|
|
14
|
+
prompt?: string;
|
|
13
15
|
}
|
|
14
16
|
/** The parts of a parsed scan a sink reads. */
|
|
15
17
|
export interface SinkScan {
|
|
@@ -30,6 +32,12 @@ export declare function resolveScanExpected(sink: ScanSink, ctx: Record<string,
|
|
|
30
32
|
* each expected value once (or as many times as expected, with 'count').
|
|
31
33
|
*/
|
|
32
34
|
export declare function scanSinkError(value: unknown, fieldSchema: Schema | undefined, ctx: Record<string, unknown> | undefined): string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* How many scans complete an array field: the scans its expected list admits
|
|
37
|
+
* (each listing under 'count', each distinct value otherwise), else
|
|
38
|
+
* `maxItems`, else null. The checklist and the admission gate share it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function scanTargetCount(fieldSchema: Schema | undefined, ctx: Record<string, unknown> | undefined): number | null;
|
|
33
41
|
/** What a scan does to a field: the next value, or the error to show (nothing written). */
|
|
34
42
|
export declare function applyScanToField(current: unknown, scan: SinkScan, fieldSchema: Schema, ctx: Record<string, unknown> | undefined): {
|
|
35
43
|
ok: true;
|
|
@@ -5,6 +5,7 @@ exports.readScanSink = readScanSink;
|
|
|
5
5
|
exports.sameScanValue = sameScanValue;
|
|
6
6
|
exports.resolveScanExpected = resolveScanExpected;
|
|
7
7
|
exports.scanSinkError = scanSinkError;
|
|
8
|
+
exports.scanTargetCount = scanTargetCount;
|
|
8
9
|
exports.applyScanToField = applyScanToField;
|
|
9
10
|
exports.pickScanSink = pickScanSink;
|
|
10
11
|
exports.wantsScanSubmit = wantsScanSubmit;
|
|
@@ -27,7 +28,9 @@ exports.scanFieldsFilled = scanFieldsFilled;
|
|
|
27
28
|
* Root `x-lt-scan-submit: true` submits once every required scan field is
|
|
28
29
|
* filled and the form validates. A string field is replaced by a scan; an
|
|
29
30
|
* array field appends, and with `multiplicity: "count"` a value expected n
|
|
30
|
-
* times takes n scans.
|
|
31
|
+
* times takes n scans. `prompt` is the empty array field's instruction (the
|
|
32
|
+
* field description when absent); the field reads `n of N` against the same
|
|
33
|
+
* expected list that admits each scan, or `maxItems`.
|
|
31
34
|
*/
|
|
32
35
|
const ctx_path_1 = require("./ctx-path");
|
|
33
36
|
exports.X_LT_SCAN = 'x-lt-scan';
|
|
@@ -50,6 +53,7 @@ function readScanSink(fieldSchema) {
|
|
|
50
53
|
...(expect?.length ? { expect } : {}),
|
|
51
54
|
expectError: typeof cfg['expect-error'] === 'string' ? cfg['expect-error'] : DEFAULT_EXPECT_ERROR,
|
|
52
55
|
multiplicity: cfg.multiplicity === 'count' ? 'count' : 'once',
|
|
56
|
+
...(typeof cfg.prompt === 'string' && cfg.prompt.trim() ? { prompt: cfg.prompt } : {}),
|
|
53
57
|
};
|
|
54
58
|
}
|
|
55
59
|
/** Manufacturer barcodes compare as GTINs, so a UPC-A matches its 14-digit form. */
|
|
@@ -102,6 +106,21 @@ function scanSinkError(value, fieldSchema, ctx) {
|
|
|
102
106
|
}
|
|
103
107
|
return undefined;
|
|
104
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* How many scans complete an array field: the scans its expected list admits
|
|
111
|
+
* (each listing under 'count', each distinct value otherwise), else
|
|
112
|
+
* `maxItems`, else null. The checklist and the admission gate share it.
|
|
113
|
+
*/
|
|
114
|
+
function scanTargetCount(fieldSchema, ctx) {
|
|
115
|
+
const sink = readScanSink(fieldSchema);
|
|
116
|
+
if (sink) {
|
|
117
|
+
const expected = resolveScanExpected(sink, ctx);
|
|
118
|
+
if (expected !== null)
|
|
119
|
+
return sink.multiplicity === 'count' ? expected.length : new Set(expected).size;
|
|
120
|
+
}
|
|
121
|
+
const max = fieldSchema?.maxItems;
|
|
122
|
+
return typeof max === 'number' ? max : null;
|
|
123
|
+
}
|
|
105
124
|
/** What a scan does to a field: the next value, or the error to show (nothing written). */
|
|
106
125
|
function applyScanToField(current, scan, fieldSchema, ctx) {
|
|
107
126
|
const sink = readScanSink(fieldSchema);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.resolveRelatedFacets = exports.resolveTemplateValue = exports.rowTemplateContext = exports.splitPathError = exports.listSchemaRelationsError = exports.readListSchemaRelations = exports.METADATA_KEY = void 0;
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
19
|
+
var validate_1 = require("./validate");
|
|
20
|
+
Object.defineProperty(exports, "METADATA_KEY", { enumerable: true, get: function () { return validate_1.METADATA_KEY; } });
|
|
21
|
+
Object.defineProperty(exports, "readListSchemaRelations", { enumerable: true, get: function () { return validate_1.readListSchemaRelations; } });
|
|
22
|
+
Object.defineProperty(exports, "listSchemaRelationsError", { enumerable: true, get: function () { return validate_1.listSchemaRelationsError; } });
|
|
23
|
+
Object.defineProperty(exports, "splitPathError", { enumerable: true, get: function () { return validate_1.splitPathError; } });
|
|
24
|
+
var template_1 = require("./template");
|
|
25
|
+
Object.defineProperty(exports, "rowTemplateContext", { enumerable: true, get: function () { return template_1.rowTemplateContext; } });
|
|
26
|
+
Object.defineProperty(exports, "resolveTemplateValue", { enumerable: true, get: function () { return template_1.resolveTemplateValue; } });
|
|
27
|
+
Object.defineProperty(exports, "resolveRelatedFacets", { enumerable: true, get: function () { return template_1.resolveRelatedFacets; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type HelpTokenContext } from '../form-validation/x-lt-help';
|
|
2
|
+
/** The template domains of one escalation row, JSON-string columns parsed. */
|
|
3
|
+
export declare function rowTemplateContext(row: Record<string, unknown>): HelpTokenContext;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve one facet value. A lone `{{token}}` keeps the value's own JSON type
|
|
6
|
+
* (a numeric facet matches a numeric facet); a mixed template interpolates to
|
|
7
|
+
* a string; a literal passes through. Undefined when a token is missing.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveTemplateValue(value: unknown, ctx: HelpTokenContext): unknown;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a related query's match against a host row: every required facet
|
|
12
|
+
* (null when any is missing), plus each `narrow` facet the row resolves.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveRelatedFacets(facets: Record<string, unknown>, ctx: HelpTokenContext, narrow?: Record<string, unknown>): Record<string, unknown> | null;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rowTemplateContext = rowTemplateContext;
|
|
4
|
+
exports.resolveTemplateValue = resolveTemplateValue;
|
|
5
|
+
exports.resolveRelatedFacets = resolveRelatedFacets;
|
|
6
|
+
const x_lt_bind_1 = require("../form-validation/x-lt-bind");
|
|
7
|
+
const x_lt_help_1 = require("../form-validation/x-lt-help");
|
|
8
|
+
const SINGLE_TOKEN = /^\{\{\s*([^{}]+?)\s*\}\}$/;
|
|
9
|
+
const ANY_TOKEN = /\{\{\s*[^{}]+?\s*\}\}/;
|
|
10
|
+
const MISSING_VALUE = '—';
|
|
11
|
+
function parseJsonObject(value) {
|
|
12
|
+
if (value && typeof value === 'object')
|
|
13
|
+
return value;
|
|
14
|
+
if (typeof value !== 'string' || !value)
|
|
15
|
+
return null;
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(value);
|
|
18
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** The template domains of one escalation row, JSON-string columns parsed. */
|
|
25
|
+
function rowTemplateContext(row) {
|
|
26
|
+
return {
|
|
27
|
+
escalation: row,
|
|
28
|
+
metadata: row.metadata ?? {},
|
|
29
|
+
envelope: parseJsonObject(row.envelope) ?? {},
|
|
30
|
+
payload: parseJsonObject(row.escalation_payload) ?? {},
|
|
31
|
+
resolver: parseJsonObject(row.resolver_payload) ?? {},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function readToken(path, ctx) {
|
|
35
|
+
const dot = path.indexOf('.');
|
|
36
|
+
const domain = (dot === -1 ? path : path.slice(0, dot));
|
|
37
|
+
if (!x_lt_help_1.HELP_DOMAINS.includes(domain))
|
|
38
|
+
return undefined;
|
|
39
|
+
const root = ctx[domain];
|
|
40
|
+
if (dot === -1)
|
|
41
|
+
return root ?? undefined;
|
|
42
|
+
try {
|
|
43
|
+
return (0, x_lt_bind_1.getDeep)(root, path.slice(dot + 1));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve one facet value. A lone `{{token}}` keeps the value's own JSON type
|
|
51
|
+
* (a numeric facet matches a numeric facet); a mixed template interpolates to
|
|
52
|
+
* a string; a literal passes through. Undefined when a token is missing.
|
|
53
|
+
*/
|
|
54
|
+
function resolveTemplateValue(value, ctx) {
|
|
55
|
+
if (typeof value !== 'string')
|
|
56
|
+
return value;
|
|
57
|
+
const single = value.match(SINGLE_TOKEN);
|
|
58
|
+
if (single) {
|
|
59
|
+
const raw = readToken(single[1], ctx);
|
|
60
|
+
return raw === null || raw === '' ? undefined : raw;
|
|
61
|
+
}
|
|
62
|
+
if (!ANY_TOKEN.test(value))
|
|
63
|
+
return value;
|
|
64
|
+
const text = (0, x_lt_help_1.interpolateHelp)(value, ctx);
|
|
65
|
+
return text.includes(MISSING_VALUE) ? undefined : text;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve a related query's match against a host row: every required facet
|
|
69
|
+
* (null when any is missing), plus each `narrow` facet the row resolves.
|
|
70
|
+
*/
|
|
71
|
+
function resolveRelatedFacets(facets, ctx, narrow) {
|
|
72
|
+
const out = {};
|
|
73
|
+
for (const [key, value] of Object.entries(facets)) {
|
|
74
|
+
const resolved = resolveTemplateValue(value, ctx);
|
|
75
|
+
if (resolved === undefined)
|
|
76
|
+
return null;
|
|
77
|
+
out[key] = resolved;
|
|
78
|
+
}
|
|
79
|
+
for (const [key, value] of Object.entries(narrow ?? {})) {
|
|
80
|
+
const resolved = resolveTemplateValue(value, ctx);
|
|
81
|
+
if (resolved !== undefined)
|
|
82
|
+
out[key] = resolved;
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Related sets on a role's list schema. A set is named once under
|
|
3
|
+
* `x-lt-related`; columns (`related`) and row details (`x-lt-row-detail`)
|
|
4
|
+
* reference it by name. The server reads the declaration from the stored
|
|
5
|
+
* list schema, never from the caller.
|
|
6
|
+
*
|
|
7
|
+
* items the host row's accumulated or batch items, each read through its
|
|
8
|
+
* payload or its reciprocal row
|
|
9
|
+
* query rows in other roles that share facets with the host row; facet
|
|
10
|
+
* values are `{{domain.path}}` templates over the host row
|
|
11
|
+
*/
|
|
12
|
+
export declare const LIST_SCHEMA_KEYS: {
|
|
13
|
+
readonly RELATED: "x-lt-related";
|
|
14
|
+
readonly COLUMNS: "x-lt-columns";
|
|
15
|
+
readonly ROW_DETAIL: "x-lt-row-detail";
|
|
16
|
+
readonly GROUP_BY: "x-lt-group-by";
|
|
17
|
+
readonly LAYOUT: "x-lt-layout";
|
|
18
|
+
};
|
|
19
|
+
export declare const RELATED_SOURCES: {
|
|
20
|
+
readonly ITEMS: "items";
|
|
21
|
+
readonly QUERY: "query";
|
|
22
|
+
};
|
|
23
|
+
export type RelatedSource = (typeof RELATED_SOURCES)[keyof typeof RELATED_SOURCES];
|
|
24
|
+
export declare const RELATED_AGGREGATES: {
|
|
25
|
+
readonly COUNT: "count";
|
|
26
|
+
};
|
|
27
|
+
export type RelatedAggregate = (typeof RELATED_AGGREGATES)[keyof typeof RELATED_AGGREGATES];
|
|
28
|
+
/** How a grouped table folds a plain column across a group's rows. */
|
|
29
|
+
export declare const GROUP_FOLDS: {
|
|
30
|
+
readonly FIRST: "first";
|
|
31
|
+
readonly MIN: "min";
|
|
32
|
+
readonly MAX: "max";
|
|
33
|
+
readonly SUM: "sum";
|
|
34
|
+
readonly COUNT: "count";
|
|
35
|
+
/** The distinct values, in row order, joined: "standard, express". */
|
|
36
|
+
readonly DISTINCT: "distinct";
|
|
37
|
+
};
|
|
38
|
+
export type GroupFold = (typeof GROUP_FOLDS)[keyof typeof GROUP_FOLDS];
|
|
39
|
+
/** Split prefixes. `role` splits a query set by the related row's role. */
|
|
40
|
+
export declare const SPLIT_PATHS: {
|
|
41
|
+
readonly ROLE: "role";
|
|
42
|
+
readonly METADATA: "metadata.";
|
|
43
|
+
readonly PAYLOAD: "payload.";
|
|
44
|
+
readonly RECIPROCAL_METADATA: "reciprocal.metadata.";
|
|
45
|
+
};
|
|
46
|
+
export declare const RELATED_LIMITS: {
|
|
47
|
+
readonly MAX_SETS: 4;
|
|
48
|
+
readonly MAX_QUERY_ROLES: 12;
|
|
49
|
+
readonly MAX_ROW_DETAIL_SECTIONS: 4;
|
|
50
|
+
readonly MAX_HOSTS: 100;
|
|
51
|
+
readonly ROWS_DEFAULT: 25;
|
|
52
|
+
readonly ROWS_MAX: 100;
|
|
53
|
+
};
|
|
54
|
+
/** The table layout that renders related columns, row details, and groups. */
|
|
55
|
+
export declare const FACET_TABLE_LAYOUT = "facet-table";
|
|
56
|
+
export interface RelatedQueryDecl {
|
|
57
|
+
/** Related roles, in display order. Exclusive with `segment`. */
|
|
58
|
+
roles?: string[];
|
|
59
|
+
/** A Pace Board sequence by its first role; resolves to the ordered chain. */
|
|
60
|
+
segment?: string;
|
|
61
|
+
/** Facet containment; string values may be `{{domain.path}}` templates. */
|
|
62
|
+
facets?: Record<string, unknown>;
|
|
63
|
+
/**
|
|
64
|
+
* Facets that narrow the match when the host row carries a value, and
|
|
65
|
+
* drop away when it does not: a lane narrows its tub's look-ahead to its
|
|
66
|
+
* own service level, a tub without lanes keeps the whole destination.
|
|
67
|
+
*/
|
|
68
|
+
narrow?: Record<string, unknown>;
|
|
69
|
+
/** Default `pending`. */
|
|
70
|
+
status?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface RelatedSetDecl {
|
|
73
|
+
source: RelatedSource;
|
|
74
|
+
query?: RelatedQueryDecl;
|
|
75
|
+
}
|
|
76
|
+
export interface RelatedColumnDecl {
|
|
77
|
+
label: string;
|
|
78
|
+
related: string;
|
|
79
|
+
aggregate?: RelatedAggregate;
|
|
80
|
+
splitBy?: string;
|
|
81
|
+
labels?: Record<string, string>;
|
|
82
|
+
priority?: 1 | 2 | 3;
|
|
83
|
+
/** CSS width, as on any facet-table column. */
|
|
84
|
+
width?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface RowDetailColumnDecl {
|
|
87
|
+
label: string;
|
|
88
|
+
value: string;
|
|
89
|
+
format?: string;
|
|
90
|
+
priority?: 1 | 2 | 3;
|
|
91
|
+
}
|
|
92
|
+
export interface RowDetailSectionDecl {
|
|
93
|
+
related: string;
|
|
94
|
+
label?: string;
|
|
95
|
+
columns: RowDetailColumnDecl[];
|
|
96
|
+
limit?: number;
|
|
97
|
+
}
|
|
98
|
+
/** The validated, normalized related declaration of one list schema. */
|
|
99
|
+
export interface ListSchemaRelations {
|
|
100
|
+
sets: Record<string, RelatedSetDecl>;
|
|
101
|
+
columns: RelatedColumnDecl[];
|
|
102
|
+
rowDetail: RowDetailSectionDecl[];
|
|
103
|
+
/** The metadata key a facet-table groups by, when declared. */
|
|
104
|
+
groupKey: string | null;
|
|
105
|
+
}
|
|
106
|
+
/** Per-host aggregate for one (set, splitBy) pair. */
|
|
107
|
+
export interface RelatedHostAggregate {
|
|
108
|
+
count: number;
|
|
109
|
+
/** Split value to count; a null value is keyed by the empty string. */
|
|
110
|
+
splits?: Record<string, number>;
|
|
111
|
+
/** Items whose reciprocal row the viewer cannot read. */
|
|
112
|
+
hidden?: number;
|
|
113
|
+
/** A host whose facet templates resolved to nothing; the set did not run. */
|
|
114
|
+
unresolved?: boolean;
|
|
115
|
+
}
|
|
116
|
+
export interface RelatedSetResult {
|
|
117
|
+
source: RelatedSource;
|
|
118
|
+
/**
|
|
119
|
+
* The roles whose rows the set reads, which a list follows for live
|
|
120
|
+
* changes: a query set's resolved roles in order, or the roles of an item
|
|
121
|
+
* set's readable reciprocal rows when a column splits by them.
|
|
122
|
+
*/
|
|
123
|
+
roles?: string[];
|
|
124
|
+
/** Query sets: role titles, keyed by role. */
|
|
125
|
+
roleLabels?: Record<string, string>;
|
|
126
|
+
/** Query sets: declared roles outside the viewer's full read scope. */
|
|
127
|
+
restricted?: string[];
|
|
128
|
+
/** Keyed by splitBy ('' when unsplit), then host id. */
|
|
129
|
+
aggregates: Record<string, Record<string, RelatedHostAggregate>>;
|
|
130
|
+
}
|
|
131
|
+
export interface RelatedAggregatesResponse {
|
|
132
|
+
version: number | null;
|
|
133
|
+
sets: Record<string, RelatedSetResult>;
|
|
134
|
+
}
|
|
135
|
+
export interface RelatedItemEntry {
|
|
136
|
+
itemKey: string;
|
|
137
|
+
payload?: unknown;
|
|
138
|
+
at?: string;
|
|
139
|
+
actor?: string;
|
|
140
|
+
reciprocalId?: string;
|
|
141
|
+
}
|
|
142
|
+
export interface RelatedRow {
|
|
143
|
+
/** Items sets only. */
|
|
144
|
+
item?: RelatedItemEntry;
|
|
145
|
+
/** The reciprocal row (items) or the related row (query); null when unreadable. */
|
|
146
|
+
escalation: Record<string, unknown> | null;
|
|
147
|
+
}
|
|
148
|
+
export interface RelatedRowsResponse {
|
|
149
|
+
source: RelatedSource;
|
|
150
|
+
rows: RelatedRow[];
|
|
151
|
+
total: number;
|
|
152
|
+
restricted?: string[];
|
|
153
|
+
roleLabels?: Record<string, string>;
|
|
154
|
+
}
|