@hotmeshio/long-tail 0.28.4 → 0.30.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/build/api/roles.js +4 -0
- package/build/api/scan-codes/choice.js +6 -3
- package/build/api/scan-codes/context.d.ts +7 -1
- package/build/api/scan-codes/context.js +24 -0
- package/build/api/scan-codes/execute.js +4 -2
- package/build/api/scan-codes/present.d.ts +3 -1
- package/build/api/scan-codes/present.js +25 -12
- package/build/routes/oauth.d.ts +1 -0
- package/build/routes/oauth.js +16 -2
- package/build/services/oauth/index.d.ts +1 -0
- package/build/services/oauth/index.js +5 -1
- package/build/services/oauth/providers/github.js +2 -1
- package/build/services/oauth/providers/google.js +3 -3
- package/build/services/oauth/providers/microsoft.js +4 -1
- package/build/services/oauth/providers/mock.js +1 -1
- package/build/services/oauth/provisioning.d.ts +8 -0
- package/build/services/oauth/provisioning.js +23 -0
- package/build/services/role/scan-done.d.ts +7 -0
- package/build/services/role/scan-done.js +36 -0
- package/build/services/role/seed.js +4 -0
- package/build/services/role/types.d.ts +11 -0
- package/build/services/role/types.js +4 -0
- package/build/services/scan-code/validate.js +50 -0
- package/build/start/config.js +1 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/index.d.ts +2 -2
- package/build/types/index.js +3 -1
- package/build/types/oauth.d.ts +3 -0
- package/build/types/scan-choice.d.ts +8 -0
- package/build/types/scan-code/constants.d.ts +3 -0
- package/build/types/scan-code/constants.js +4 -1
- package/build/types/scan-code/response.d.ts +14 -0
- package/build/types/scan-code/rule.d.ts +11 -0
- package/dashboard/dist/assets/{AdminDashboard-DRE0hSDS.js → AdminDashboard-Bjf_7-S6.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DRE0hSDS.js.map → AdminDashboard-Bjf_7-S6.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-BuflQGgy.js → AgentConfigPage-CEGk5Gbv.js} +6 -6
- package/dashboard/dist/assets/{AgentConfigPage-BuflQGgy.js.map → AgentConfigPage-CEGk5Gbv.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-BiL9FB7i.js → AgentDetailPage-C52Oi1_f.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-BiL9FB7i.js.map → AgentDetailPage-C52Oi1_f.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-C4ZxCNxt.js → AgentsPage-CohqxaWS.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-C4ZxCNxt.js.map → AgentsPage-CohqxaWS.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-B5p8QJvI.js → AvailableEscalationsPage-DXpRnOVd.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-B5p8QJvI.js.map → AvailableEscalationsPage-DXpRnOVd.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-B7V77PnY.js → BotPicker-DPglulL6.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-B7V77PnY.js.map → BotPicker-DPglulL6.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-DcGVMQqm.js → BulkAssignModal-DWNR3FJJ.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-DcGVMQqm.js.map → BulkAssignModal-DWNR3FJJ.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-DmbC1pEs.js → CapabilitiesPage-ChBBD0IX.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-DmbC1pEs.js.map → CapabilitiesPage-ChBBD0IX.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-C81S1qic.js → CollapsibleSection-QAXKTYc6.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-C81S1qic.js.map → CollapsibleSection-QAXKTYc6.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-3RFyWN9Q.js → ConfirmDeleteModal-J9xc_gVZ.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-3RFyWN9Q.js.map → ConfirmDeleteModal-J9xc_gVZ.js.map} +1 -1
- package/dashboard/dist/assets/{ConnectedAppsPage-B0D2OvTD.js → ConnectedAppsPage-BKhsc_jJ.js} +2 -2
- package/dashboard/dist/assets/{ConnectedAppsPage-B0D2OvTD.js.map → ConnectedAppsPage-BKhsc_jJ.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-iAG28fzG.js → CountdownTimer-C4hP64lF.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-iAG28fzG.js.map → CountdownTimer-C4hP64lF.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-DoFwNvFv.js → CredentialsPage-DUfgsEbI.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-DoFwNvFv.js.map → CredentialsPage-DUfgsEbI.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-C1Bb2wo4.js → CronLabel-CBc3Tvau.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-C1Bb2wo4.js.map → CronLabel-CBc3Tvau.js.map} +1 -1
- package/dashboard/dist/assets/{DropZone-Cl_Flb16.js → DropZone-DefYTYQy.js} +2 -2
- package/dashboard/dist/assets/{DropZone-Cl_Flb16.js.map → DropZone-DefYTYQy.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-DZs1I1JW.js → ElapsedCell-V27Y2Ksb.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-DZs1I1JW.js.map → ElapsedCell-V27Y2Ksb.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-Du1O6Oly.js → EntityTimelinePanel-BA4MWXkB.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-Du1O6Oly.js.map → EntityTimelinePanel-BA4MWXkB.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-CrpBhC0e.js → EscalationListSchemaPage-B20HUAlO.js} +2 -2
- package/dashboard/dist/assets/{EscalationListSchemaPage-CrpBhC0e.js.map → EscalationListSchemaPage-B20HUAlO.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-Co59lcuD.js → EscalationSchemaPage-Cen9HGYG.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-Co59lcuD.js.map → EscalationSchemaPage-Cen9HGYG.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-B_fzNsX5.js → EscalationTimeline-DGNgcMm0.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-B_fzNsX5.js.map → EscalationTimeline-DGNgcMm0.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-C2Goebjo.js → EscalationTitleSelect-BhsflGiC.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-C2Goebjo.js.map → EscalationTitleSelect-BhsflGiC.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-Cgmrl8Zc.js → EscalationsOverview-C2nc-Pgv.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-Cgmrl8Zc.js.map → EscalationsOverview-C2nc-Pgv.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-BdEiu3Fv.js → EventTable-BvNxHKy1.js} +2 -2
- package/dashboard/dist/assets/{EventTable-BdEiu3Fv.js.map → EventTable-BvNxHKy1.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-CzKYBOMC.js → FilterBar-22FDO0R_.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-CzKYBOMC.js.map → FilterBar-22FDO0R_.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-CcDFhY53.js → GraphInvokePage-BAyfJ-PY.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-CcDFhY53.js.map → GraphInvokePage-BAyfJ-PY.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-Xahqcdu9.js → HomePage-CtjG2kGn.js} +2 -2
- package/dashboard/dist/assets/{HomePage-Xahqcdu9.js.map → HomePage-CtjG2kGn.js.map} +1 -1
- package/dashboard/dist/assets/{LinePage-DKwhGunp.js → LinePage-DPe-vP3-.js} +3 -3
- package/dashboard/dist/assets/{LinePage-DKwhGunp.js.map → LinePage-DPe-vP3-.js.map} +1 -1
- package/dashboard/dist/assets/{LinesPage-BXZVO4MC.js → LinesPage-BCSfYkuL.js} +2 -2
- package/dashboard/dist/assets/{LinesPage-BXZVO4MC.js.map → LinesPage-BCSfYkuL.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-orQsOdl_.js → ListToolbar-6siR0Hao.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-orQsOdl_.js.map → ListToolbar-6siR0Hao.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-pSnadtSM.js → McpOverview-Cbu2CXlQ.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-pSnadtSM.js.map → McpOverview-Cbu2CXlQ.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BCAJ3rKO.js → McpQueryDetailPage--1FsnGuM.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BCAJ3rKO.js.map → McpQueryDetailPage--1FsnGuM.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-CRyXeRp5.js → McpQueryPage-CPUUMIiY.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CRyXeRp5.js.map → McpQueryPage-CPUUMIiY.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-BHppCztI.js → McpRunDetailPage-BDCv-c1o.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-BHppCztI.js.map → McpRunDetailPage-BDCv-c1o.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-Cd9yCT-_.js → McpRunsPage-Df4yOclO.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-Cd9yCT-_.js.map → McpRunsPage-Df4yOclO.js.map} +1 -1
- package/dashboard/dist/assets/{NamespacePill-OTZD2hzt.js → NamespacePill-CeSfHH-j.js} +2 -2
- package/dashboard/dist/assets/{NamespacePill-OTZD2hzt.js.map → NamespacePill-CeSfHH-j.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-BtnthZgj.js → OperationsPage-BYUGFgPp.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-BtnthZgj.js.map → OperationsPage-BYUGFgPp.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-B4_OBhYh.js → OperatorDashboard-Dd1EhTZe.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-B4_OBhYh.js.map → OperatorDashboard-Dd1EhTZe.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeader-Hx8APPwE.js → PageHeader-DiGWAQlR.js} +2 -2
- package/dashboard/dist/assets/{PageHeader-Hx8APPwE.js.map → PageHeader-DiGWAQlR.js.map} +1 -1
- package/dashboard/dist/assets/{PageHeaderWithStats-BEQYYBJv.js → PageHeaderWithStats-DwnKQ06j.js} +2 -2
- package/dashboard/dist/assets/{PageHeaderWithStats-BEQYYBJv.js.map → PageHeaderWithStats-DwnKQ06j.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-BAYjM9qf.js → PersonaDetailPage-BCx3Ey2_.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-BAYjM9qf.js.map → PersonaDetailPage-BCx3Ey2_.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-6HsOp-1y.js → PersonasPage--Ez0YeHh.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-6HsOp-1y.js.map → PersonasPage--Ez0YeHh.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-6OMr7KtJ.js → PortalPage-BmBmheBp.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-6OMr7KtJ.js.map → PortalPage-BmBmheBp.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-AidH_h7z.js → ProcessDetailPage-DBj4VEnP.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-AidH_h7z.js.map → ProcessDetailPage-DBj4VEnP.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-BWKoKbXk.js → ProcessesListPage-CD5NRIBK.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-BWKoKbXk.js.map → ProcessesListPage-CD5NRIBK.js.map} +1 -1
- package/dashboard/dist/assets/{ResolverForm-BaSvhLoT.js → ResolverForm-Baxwv_IG.js} +2 -2
- package/dashboard/dist/assets/{ResolverForm-BaSvhLoT.js.map → ResolverForm-Baxwv_IG.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-6ukNyycs.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-6ukNyycs.js.map +1 -0
- package/dashboard/dist/assets/{RolePill-R5_ctGFy.js → RolePill-D3hkAdKf.js} +2 -2
- package/dashboard/dist/assets/{RolePill-R5_ctGFy.js.map → RolePill-D3hkAdKf.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-T2hH_MV5.js → RolesPage-DRs2XeSd.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-T2hH_MV5.js.map → RolesPage-DRs2XeSd.js.map} +1 -1
- package/dashboard/dist/assets/{RosterWidget-DG6Rcx4P.js → RosterWidget-BPBPSa1k.js} +2 -2
- package/dashboard/dist/assets/{RosterWidget-DG6Rcx4P.js.map → RosterWidget-BPBPSa1k.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-M2h9U6PP.js → RunAsSelector-Br9FiMwP.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-M2h9U6PP.js.map → RunAsSelector-Br9FiMwP.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-lB_WxoZw.js → ScanCodesPage-BXENWoZb.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-lB_WxoZw.js.map → ScanCodesPage-BXENWoZb.js.map} +1 -1
- package/dashboard/dist/assets/{ScanSchemeDetailPage-C3VLg61H.js → ScanSchemeDetailPage-CaM4rUBV.js} +2 -2
- package/dashboard/dist/assets/{ScanSchemeDetailPage-C3VLg61H.js.map → ScanSchemeDetailPage-CaM4rUBV.js.map} +1 -1
- package/dashboard/dist/assets/ScanStationPage-CmJKgWy_.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-CmJKgWy_.js.map +1 -0
- package/dashboard/dist/assets/{ScopeBadge-BXZ084nD.js → ScopeBadge-DGz79rmG.js} +2 -2
- package/dashboard/dist/assets/{ScopeBadge-BXZ084nD.js.map → ScopeBadge-DGz79rmG.js.map} +1 -1
- package/dashboard/dist/assets/{StickyPagination-BdjseWXr.js → StickyPagination-DX5CPgrX.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BdjseWXr.js.map → StickyPagination-DX5CPgrX.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-DJCBxETh.js → StreamMessageDetail-3mWw3_M5.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-DJCBxETh.js.map → StreamMessageDetail-3mWw3_M5.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-DiXm9jIk.js → SwimlaneTimeline-C_pIcWBJ.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-DiXm9jIk.js.map → SwimlaneTimeline-C_pIcWBJ.js.map} +1 -1
- package/dashboard/dist/assets/{TagInput-DjPUDp2M.js → TagInput-DaIdhv3h.js} +2 -2
- package/dashboard/dist/assets/{TagInput-DjPUDp2M.js.map → TagInput-DaIdhv3h.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-m8CQFN4w.js → TaskDetailPage-DthMVBZO.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-m8CQFN4w.js.map → TaskDetailPage-DthMVBZO.js.map} +1 -1
- package/dashboard/dist/assets/{TaskQueuePill-D-4Ynf3K.js → TaskQueuePill-sUA1nZe-.js} +2 -2
- package/dashboard/dist/assets/{TaskQueuePill-D-4Ynf3K.js.map → TaskQueuePill-sUA1nZe-.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-DHBSUhZC.js → TasksListPage-MtawUpuU.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-DHBSUhZC.js.map → TasksListPage-MtawUpuU.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-Cq3bKUd-.js → TimeAgo-DIziYk-v.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-Cq3bKUd-.js.map → TimeAgo-DIziYk-v.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-e5gRR_FY.js → TimestampCell-Dn5M-Eey.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-e5gRR_FY.js.map → TimestampCell-Dn5M-Eey.js.map} +1 -1
- package/dashboard/dist/assets/{ToolPill-GsKQ80CO.js → ToolPill-CpBAFdEX.js} +2 -2
- package/dashboard/dist/assets/{ToolPill-GsKQ80CO.js.map → ToolPill-CpBAFdEX.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-Bg0ss9oN.js → ToolTestPanel-DaBrgPML.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-Bg0ss9oN.js.map → ToolTestPanel-DaBrgPML.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DhPiCfOO.js → TopicDetailPage-zNE3EigP.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-DhPiCfOO.js.map → TopicDetailPage-zNE3EigP.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-BqZaVv3d.js → TopicsPage-Cj0ugdie.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-BqZaVv3d.js.map → TopicsPage-Cj0ugdie.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-C6ZNHHKN.js → UserName-t3PbLYfd.js} +2 -2
- package/dashboard/dist/assets/{UserName-C6ZNHHKN.js.map → UserName-t3PbLYfd.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-BUqIhtcr.js → WorkflowExecutionPage-CZ2c5QLL.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-BUqIhtcr.js.map → WorkflowExecutionPage-CZ2c5QLL.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowPill-D7244fKp.js → WorkflowPill-CKHip3hH.js} +2 -2
- package/dashboard/dist/assets/{WorkflowPill-D7244fKp.js.map → WorkflowPill-CKHip3hH.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-BKxhC_hT.js → WorkflowsDashboard-DLb71Sa2.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-BKxhC_hT.js.map → WorkflowsDashboard-DLb71Sa2.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-018s2q_p.js → WorkflowsOverview-Wz6RzxHJ.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-018s2q_p.js.map → WorkflowsOverview-Wz6RzxHJ.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-C2zcXDr1.js → YamlWorkflowDetailPage-CcRAN_ey.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-C2zcXDr1.js.map → YamlWorkflowDetailPage-CcRAN_ey.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-aVcNZNu6.js → YamlWorkflowsPage-B4C9fiYU.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-aVcNZNu6.js.map → YamlWorkflowsPage-B4C9fiYU.js.map} +1 -1
- package/dashboard/dist/assets/{agents-DRaaJUue.js → agents-BvRjwrof.js} +2 -2
- package/dashboard/dist/assets/{agents-DRaaJUue.js.map → agents-BvRjwrof.js.map} +1 -1
- package/dashboard/dist/assets/{bots-C4N90NCj.js → bots-qx7qPwFo.js} +2 -2
- package/dashboard/dist/assets/{bots-C4N90NCj.js.map → bots-qx7qPwFo.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-BoRWifSC.js → capabilities-DJrUEeew.js} +2 -2
- package/dashboard/dist/assets/{capabilities-BoRWifSC.js.map → capabilities-DJrUEeew.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DGZAxi7J.js → controlplane-D82a5cfq.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DGZAxi7J.js.map → controlplane-D82a5cfq.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-DJbfsH_m.js → escalation-columns-Dmm8LY_f.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-DJbfsH_m.js.map → escalation-columns-Dmm8LY_f.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-items-C8iJZEA8.js → escalation-items-C3ko1DCb.js} +2 -2
- package/dashboard/dist/assets/{escalation-items-C8iJZEA8.js.map → escalation-items-C3ko1DCb.js.map} +1 -1
- package/dashboard/dist/assets/{index-BuSUevzO.js → index-BAxEeqfF.js} +2 -2
- package/dashboard/dist/assets/{index-BuSUevzO.js.map → index-BAxEeqfF.js.map} +1 -1
- package/dashboard/dist/assets/{index-DhKGp4QK.js → index-BCSeHOZH.js} +2 -2
- package/dashboard/dist/assets/{index-DhKGp4QK.js.map → index-BCSeHOZH.js.map} +1 -1
- package/dashboard/dist/assets/{index-DeyA88jq.js → index-BJrsQM-E.js} +2 -2
- package/dashboard/dist/assets/{index-DeyA88jq.js.map → index-BJrsQM-E.js.map} +1 -1
- package/dashboard/dist/assets/{index-CXXc9sUr.js → index-BVxqddYr.js} +2 -2
- package/dashboard/dist/assets/{index-CXXc9sUr.js.map → index-BVxqddYr.js.map} +1 -1
- package/dashboard/dist/assets/{index-DIU89TX3.js → index-C59ZyWOo.js} +2 -2
- package/dashboard/dist/assets/{index-DIU89TX3.js.map → index-C59ZyWOo.js.map} +1 -1
- package/dashboard/dist/assets/{index-CyL-6CAa.js → index-CNDnGdvT.js} +2 -2
- package/dashboard/dist/assets/{index-CyL-6CAa.js.map → index-CNDnGdvT.js.map} +1 -1
- package/dashboard/dist/assets/{index-pzbGpihI.js → index-CSr5q355.js} +25 -25
- package/dashboard/dist/assets/index-CSr5q355.js.map +1 -0
- package/dashboard/dist/assets/{index-DMKLnxt8.js → index-CXnmU0TS.js} +2 -2
- package/dashboard/dist/assets/{index-DMKLnxt8.js.map → index-CXnmU0TS.js.map} +1 -1
- package/dashboard/dist/assets/{index-CjjRxpVe.js → index-C_-FoMo9.js} +2 -2
- package/dashboard/dist/assets/{index-CjjRxpVe.js.map → index-C_-FoMo9.js.map} +1 -1
- package/dashboard/dist/assets/index-C_dp4WgY.css +1 -0
- package/dashboard/dist/assets/{index-3HaFP00M.js → index-D-vNL8Hm.js} +2 -2
- package/dashboard/dist/assets/{index-3HaFP00M.js.map → index-D-vNL8Hm.js.map} +1 -1
- package/dashboard/dist/assets/{index-BFxHIfQ_.js → index-DOkHnsLK.js} +2 -2
- package/dashboard/dist/assets/{index-BFxHIfQ_.js.map → index-DOkHnsLK.js.map} +1 -1
- package/dashboard/dist/assets/{index-BhS9XSy8.js → index-U5gC9Xgq.js} +2 -2
- package/dashboard/dist/assets/{index-BhS9XSy8.js.map → index-U5gC9Xgq.js.map} +1 -1
- package/dashboard/dist/assets/{index-CeeSFnl-.js → index-f4-pKYcm.js} +2 -2
- package/dashboard/dist/assets/{index-CeeSFnl-.js.map → index-f4-pKYcm.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-BWo3OCJc.js → knowledge-i7_nXSbf.js} +2 -2
- package/dashboard/dist/assets/{knowledge-BWo3OCJc.js.map → knowledge-i7_nXSbf.js.map} +1 -1
- package/dashboard/dist/assets/{machines-LEYY_yar.js → machines-DfSNshLg.js} +2 -2
- package/dashboard/dist/assets/{machines-LEYY_yar.js.map → machines-DfSNshLg.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-_0kFRcyT.js → mcp-dCLNwcC8.js} +2 -2
- package/dashboard/dist/assets/{mcp-_0kFRcyT.js.map → mcp-dCLNwcC8.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BzmN0lc5.js → mcp-query-wmbaGRYi.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BzmN0lc5.js.map → mcp-query-wmbaGRYi.js.map} +1 -1
- package/dashboard/dist/assets/{personas-kE4PMrgo.js → personas-B_cJA5UG.js} +2 -2
- package/dashboard/dist/assets/{personas-kE4PMrgo.js.map → personas-B_cJA5UG.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-DYDNaypF.js → pipelines-ClUmuwmY.js} +2 -2
- package/dashboard/dist/assets/{pipelines-DYDNaypF.js.map → pipelines-ClUmuwmY.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-ClJ-mbj9.js → tasks-BE97GrLr.js} +2 -2
- package/dashboard/dist/assets/{tasks-ClJ-mbj9.js.map → tasks-BE97GrLr.js.map} +1 -1
- package/dashboard/dist/assets/{topics-oHX4vbqe.js → topics-Dk0Y3kZP.js} +2 -2
- package/dashboard/dist/assets/{topics-oHX4vbqe.js.map → topics-Dk0Y3kZP.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-C97KADrj.js → useDebouncedValue-BLGuHd_v.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-C97KADrj.js.map → useDebouncedValue-BLGuHd_v.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-Kje0Rn7j.js → useNamespace-Cj7t8eQd.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Kje0Rn7j.js.map → useNamespace-Cj7t8eQd.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-DMz-HKFv.js → useYamlActivityEvents-C7eurSkD.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-DMz-HKFv.js.map → useYamlActivityEvents-C7eurSkD.js.map} +1 -1
- package/dashboard/dist/assets/{validate-hUqjWN63.js → validate-BypZfZ8R.js} +2 -2
- package/dashboard/dist/assets/{validate-hUqjWN63.js.map → validate-BypZfZ8R.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-fxBvvHBi.js → vendor-icons-en0_uSRD.js} +191 -186
- package/dashboard/dist/assets/vendor-icons-en0_uSRD.js.map +1 -0
- package/dashboard/dist/assets/{yaml-workflows-64vfmKJx.js → yaml-workflows-CnMKmznF.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-64vfmKJx.js.map → yaml-workflows-CnMKmznF.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/roles.md +1 -1
- package/docs/dashboard.md +2 -2
- package/docs/oauth-and-delegation.md +6 -1
- package/docs/scan-codes.md +56 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/RoleDetailPage-D_30TDVh.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-D_30TDVh.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-CVET1_4r.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-CVET1_4r.js.map +0 -1
- package/dashboard/dist/assets/index-B9uv-euR.css +0 -1
- package/dashboard/dist/assets/index-pzbGpihI.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +0 -1
package/build/api/roles.js
CHANGED
|
@@ -50,6 +50,7 @@ exports.deleteRole = deleteRole;
|
|
|
50
50
|
const roleService = __importStar(require("../services/role"));
|
|
51
51
|
const types_1 = require("../services/role/types");
|
|
52
52
|
const badge_grant_1 = require("../services/role/badge-grant");
|
|
53
|
+
const scan_done_1 = require("../services/role/scan-done");
|
|
53
54
|
const facet_sql_1 = require("../services/escalation/facet-sql");
|
|
54
55
|
const list_schema_1 = require("../shared/list-schema");
|
|
55
56
|
/**
|
|
@@ -296,6 +297,9 @@ async function updateRole(input) {
|
|
|
296
297
|
const grantError = (0, badge_grant_1.badgeGrantError)(input.properties?.[types_1.ROLE_PROPERTY_KEYS.BADGE_GRANT]);
|
|
297
298
|
if (grantError)
|
|
298
299
|
return { status: 400, error: grantError };
|
|
300
|
+
const scanDoneProblem = (0, scan_done_1.scanDoneError)(input.properties?.[types_1.ROLE_PROPERTY_KEYS.SCAN_DONE]);
|
|
301
|
+
if (scanDoneProblem)
|
|
302
|
+
return { status: 400, error: scanDoneProblem };
|
|
299
303
|
const listSchemaError = input.list_schema != null ? (0, list_schema_1.listSchemaRelationsError)(input.list_schema) : null;
|
|
300
304
|
if (listSchemaError)
|
|
301
305
|
return { status: 400, error: `list_schema: ${listSchemaError}` };
|
|
@@ -41,6 +41,7 @@ const identity_1 = require("./identity");
|
|
|
41
41
|
const grant_1 = require("./grant");
|
|
42
42
|
const helpers_1 = require("../escalations/helpers");
|
|
43
43
|
const context_1 = require("./context");
|
|
44
|
+
const present_1 = require("./present");
|
|
44
45
|
const choice_roles_1 = require("./choice-roles");
|
|
45
46
|
const x_lt_actions_1 = require("../../shared/form-validation/x-lt-actions");
|
|
46
47
|
const locate_1 = require("./locate");
|
|
@@ -134,12 +135,14 @@ async function executeScanChoice(input, auth) {
|
|
|
134
135
|
// same double-actor race a second scan loses.
|
|
135
136
|
const located = await (0, locate_1.locateForStep)(step, ctx, 2);
|
|
136
137
|
const presented = located?.escalations.find((e) => e.id === input.escalationId);
|
|
137
|
-
if (!presented) {
|
|
138
|
+
if (!presented || !(0, present_1.choiceOffered)(choice, presented)) {
|
|
138
139
|
return decorate((0, context_1.conflict)('the item is no longer in the presented state'), ctx, input);
|
|
139
140
|
}
|
|
140
|
-
// 7. Dispatch through the same atomic executors a direct scan uses
|
|
141
|
+
// 7. Dispatch through the same atomic executors a direct scan uses; the
|
|
142
|
+
// choice's done copy reads the row it acted on.
|
|
141
143
|
const synthesized = { query: step.query, verb: choice.verb, params: choice.params };
|
|
142
|
-
const
|
|
144
|
+
const tpl = { ...(0, context_1.templateContext)(ctx), item: presented.metadata ?? {} };
|
|
145
|
+
const result = decorate((0, context_1.withDone)(await (0, verbs_1.dispatchChoiceVerb)(synthesized, ctx, presented), choice, tpl), ctx, input);
|
|
143
146
|
// 8. Settle the badge: refund a spend whose act did not land
|
|
144
147
|
const acting = await (0, grant_1.settleGrant)(ctx, result);
|
|
145
148
|
if (acting && result.data)
|
|
@@ -78,4 +78,10 @@ export declare function templated<T>(step: ScanStep, ctx: StepContext, render: (
|
|
|
78
78
|
* bags the copy may read (the container a subject step located, a fill's
|
|
79
79
|
* batch); an unreadable token renders empty rather than failing the act.
|
|
80
80
|
*/
|
|
81
|
-
export declare function withDone(result: LTApiResult<ScanExecuteResponse>, step: ScanStep, tpl: scanCodeService.ScanTemplateContext): LTApiResult<ScanExecuteResponse>;
|
|
81
|
+
export declare function withDone(result: LTApiResult<ScanExecuteResponse>, step: Pick<ScanStep, 'done'>, tpl: scanCodeService.ScanTemplateContext): LTApiResult<ScanExecuteResponse>;
|
|
82
|
+
/**
|
|
83
|
+
* Attach the step's `follow` to a write that completed the held subject: the
|
|
84
|
+
* code the station replays and the target it waits for, so the subject's
|
|
85
|
+
* next row is held without scanning it again.
|
|
86
|
+
*/
|
|
87
|
+
export declare function withFollow(result: LTApiResult<ScanExecuteResponse>, step: Pick<ScanStep, 'follow'>, ctx: StepContext): LTApiResult<ScanExecuteResponse>;
|
|
@@ -47,6 +47,7 @@ exports.notPrimed = notPrimed;
|
|
|
47
47
|
exports.refused = refused;
|
|
48
48
|
exports.templated = templated;
|
|
49
49
|
exports.withDone = withDone;
|
|
50
|
+
exports.withFollow = withFollow;
|
|
50
51
|
const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
51
52
|
const escalationService = __importStar(require("../../services/escalation"));
|
|
52
53
|
const types_1 = require("../../types");
|
|
@@ -160,3 +161,26 @@ function withDone(result, step, tpl) {
|
|
|
160
161
|
return result;
|
|
161
162
|
return { ...result, data: { ...data, done: { markdown: scanCodeService.renderScanCopy(step.done.markdown, tpl) } } };
|
|
162
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Attach the step's `follow` to a write that completed the held subject: the
|
|
166
|
+
* code the station replays and the target it waits for, so the subject's
|
|
167
|
+
* next row is held without scanning it again.
|
|
168
|
+
*/
|
|
169
|
+
function withFollow(result, step, ctx) {
|
|
170
|
+
const data = result.data;
|
|
171
|
+
const subject = ctx.subject;
|
|
172
|
+
if (!step.follow || !subject || !data || data.outcome !== types_1.SCAN_OUTCOMES.EXECUTED || !data.clearSubject)
|
|
173
|
+
return result;
|
|
174
|
+
return {
|
|
175
|
+
...result,
|
|
176
|
+
data: {
|
|
177
|
+
...data,
|
|
178
|
+
follow: {
|
|
179
|
+
code: subject.code,
|
|
180
|
+
roles: step.follow.roles,
|
|
181
|
+
waitSeconds: step.follow.waitSeconds ?? types_1.SCAN_FOLLOW_WAIT_DEFAULT_SECONDS,
|
|
182
|
+
target: { facet: subject.scheme.target_facet, value: subject.parsed.target },
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
@@ -114,8 +114,10 @@ async function executeScanCode(input, auth) {
|
|
|
114
114
|
let result = null;
|
|
115
115
|
for (let i = 0; i < rule.steps.length && !result; i++) {
|
|
116
116
|
const stepResult = await executeStep(rule.steps[i], ctx);
|
|
117
|
-
if (stepResult)
|
|
118
|
-
|
|
117
|
+
if (stepResult) {
|
|
118
|
+
const step = rule.steps[i];
|
|
119
|
+
result = decorate((0, context_1.withFollow)((0, context_1.withDone)(stepResult, step, (0, context_1.templateContext)(ctx)), step, ctx), ctx, i);
|
|
120
|
+
}
|
|
119
121
|
}
|
|
120
122
|
// 4. Nothing matched: a stale subject, or the fallback screen
|
|
121
123
|
if (!result) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { type ScanExecuteResponse, type ScanStep } from '../../types';
|
|
1
|
+
import { type LTEscalationRecord, type ScanChoice, type ScanExecuteResponse, type ScanStep } from '../../types';
|
|
2
2
|
import type { LTApiResult } from '../../types/sdk';
|
|
3
3
|
import { type StepContext } from './context';
|
|
4
|
+
/** True when the row carries every facet value the choice is offered under. */
|
|
5
|
+
export declare function choiceOffered(choice: Pick<ScanChoice, 'when'>, row: LTEscalationRecord): boolean;
|
|
4
6
|
/**
|
|
5
7
|
* Locate the target and present the step's choices. Choices whose identity
|
|
6
8
|
* requirement is unsatisfied come back withheld — the screen renders the
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.choiceOffered = choiceOffered;
|
|
36
37
|
exports.presentStep = presentStep;
|
|
37
38
|
const scanCodeService = __importStar(require("../../services/scan-code"));
|
|
38
39
|
const types_1 = require("../../types");
|
|
@@ -41,6 +42,11 @@ const choice_roles_1 = require("./choice-roles");
|
|
|
41
42
|
const locate_1 = require("./locate");
|
|
42
43
|
const verbs_1 = require("./verbs");
|
|
43
44
|
const context_1 = require("./context");
|
|
45
|
+
/** True when the row carries every facet value the choice is offered under. */
|
|
46
|
+
function choiceOffered(choice, row) {
|
|
47
|
+
const meta = (row.metadata ?? {});
|
|
48
|
+
return Object.entries(choice.when ?? {}).every(([key, value]) => meta[key] === value);
|
|
49
|
+
}
|
|
44
50
|
/** The step's facts rendered against the presented row; unreadable tokens render empty. */
|
|
45
51
|
function renderFacts(step, ctx, row) {
|
|
46
52
|
if (!step.facts)
|
|
@@ -83,19 +89,26 @@ async function presentStep(step, ctx) {
|
|
|
83
89
|
const roleHeld = await Promise.all((step.choices ?? []).map((choice) => (0, choice_roles_1.holdsChoiceRole)(choice, ctx.auth.userId)));
|
|
84
90
|
const only = step.choices?.length === 1 ? step.choices[0] : undefined;
|
|
85
91
|
const autoSelect = step.autoSelectSingle === true && only !== undefined && !only.confirm;
|
|
86
|
-
if (autoSelect && (!only.requireActingIdentity || satisfied) && roleHeld[0]) {
|
|
87
|
-
|
|
92
|
+
if (autoSelect && (!only.requireActingIdentity || satisfied) && roleHeld[0] && choiceOffered(only, escalation)) {
|
|
93
|
+
const tpl = { ...(0, context_1.templateContext)(ctx), item: escalation.metadata ?? {} };
|
|
94
|
+
return (0, context_1.withDone)(await (0, verbs_1.dispatchChoiceVerb)({ query: step.query, verb: only.verb, params: only.params }, ctx, escalation), only, tpl);
|
|
88
95
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
// A choice the row's state does not offer, or one hidden from a person
|
|
97
|
+
// without its roles, is left off the screen; the index stays the config's.
|
|
98
|
+
const choices = (step.choices ?? []).flatMap((choice, index) => {
|
|
99
|
+
if (!choiceOffered(choice, escalation) || (choice.hidden && !roleHeld[index]))
|
|
100
|
+
return [];
|
|
101
|
+
return [{
|
|
102
|
+
index,
|
|
103
|
+
label: choice.label,
|
|
104
|
+
verb: choice.verb,
|
|
105
|
+
...(choice.confirm ? { confirm: choice.confirm } : {}),
|
|
106
|
+
...(choice.requireActingIdentity ? { requireActingIdentity: true } : {}),
|
|
107
|
+
...(choice.roles?.length ? { roles: choice.roles } : {}),
|
|
108
|
+
...(choice.code ? { code: choice.code } : {}),
|
|
109
|
+
withheld: (!!choice.requireActingIdentity && !satisfied) || !roleHeld[index],
|
|
110
|
+
}];
|
|
111
|
+
});
|
|
99
112
|
return {
|
|
100
113
|
status: 200,
|
|
101
114
|
data: {
|
package/build/routes/oauth.d.ts
CHANGED
package/build/routes/oauth.js
CHANGED
|
@@ -5,13 +5,17 @@ const http_1 = require("../lib/http");
|
|
|
5
5
|
const auth_1 = require("../modules/auth");
|
|
6
6
|
const logger_1 = require("../lib/logger");
|
|
7
7
|
const oauth_1 = require("../services/oauth");
|
|
8
|
+
const provisioning_1 = require("../services/oauth/provisioning");
|
|
8
9
|
const user_1 = require("../services/user");
|
|
9
10
|
const router = (0, http_1.Router)();
|
|
11
|
+
// What a refused person reads. The reason is logged, never shown.
|
|
12
|
+
const SIGN_IN_REFUSED = 'This account is not allowed to sign in here. Contact an administrator.';
|
|
10
13
|
// ── OAuth startup config (set by initializeOAuth) ────────────────────────────
|
|
11
14
|
let _oauthConfig = {
|
|
12
15
|
autoProvision: true,
|
|
13
16
|
defaultRoleType: 'member',
|
|
14
17
|
baseUrl: '',
|
|
18
|
+
allowedDomains: [],
|
|
15
19
|
};
|
|
16
20
|
function setOAuthConfig(cfg) {
|
|
17
21
|
if (cfg.autoProvision !== undefined)
|
|
@@ -20,6 +24,8 @@ function setOAuthConfig(cfg) {
|
|
|
20
24
|
_oauthConfig.defaultRoleType = cfg.defaultRoleType;
|
|
21
25
|
if (cfg.baseUrl)
|
|
22
26
|
_oauthConfig.baseUrl = cfg.baseUrl;
|
|
27
|
+
if (cfg.allowedDomains)
|
|
28
|
+
_oauthConfig.allowedDomains = (0, provisioning_1.normalizeDomains)(cfg.allowedDomains);
|
|
23
29
|
}
|
|
24
30
|
/**
|
|
25
31
|
* GET /api/auth/oauth/providers
|
|
@@ -115,12 +121,20 @@ router.get('/:provider/callback', async (req, res) => {
|
|
|
115
121
|
// Find or create the user
|
|
116
122
|
let user = await (0, oauth_1.getUserByOAuthProvider)(provider, userInfo.providerUserId);
|
|
117
123
|
if (!user && userInfo.email) {
|
|
118
|
-
//
|
|
124
|
+
// A provider id meets an invited account once, by its verified email
|
|
119
125
|
user = await (0, user_1.getUserByEmail)(userInfo.email);
|
|
126
|
+
if (user)
|
|
127
|
+
logger_1.loggerRegistry.info(`[oauth] bound ${provider} id to existing account ${user.id} by verified email`);
|
|
120
128
|
}
|
|
121
129
|
if (!user) {
|
|
122
130
|
if (!_oauthConfig.autoProvision) {
|
|
123
|
-
|
|
131
|
+
logger_1.loggerRegistry.warn(`[oauth] refused ${provider} sign-in: no account and auto-provision is off`);
|
|
132
|
+
res.redirect(`/login?error=${encodeURIComponent(SIGN_IN_REFUSED)}`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!(0, provisioning_1.mayProvision)(userInfo.email, _oauthConfig.allowedDomains)) {
|
|
136
|
+
logger_1.loggerRegistry.warn(`[oauth] refused ${provider} sign-in: email domain not in allowedDomains`);
|
|
137
|
+
res.redirect(`/login?error=${encodeURIComponent(SIGN_IN_REFUSED)}`);
|
|
124
138
|
return;
|
|
125
139
|
}
|
|
126
140
|
// Auto-provision new user
|
|
@@ -2,6 +2,7 @@ import type { LTOAuthStartConfig } from '../../types/oauth';
|
|
|
2
2
|
export { encrypt, decrypt, getEncryptionKey, setEncryptionKey } from './crypto';
|
|
3
3
|
export { createOAuthState, consumeOAuthState } from './state';
|
|
4
4
|
export { registerProvider, getProvider, listProviders } from './providers';
|
|
5
|
+
export { normalizeDomains, emailDomain, mayProvision } from './provisioning';
|
|
5
6
|
export type { ProviderHandler, OAuthTokens } from './providers';
|
|
6
7
|
export { upsertOAuthToken, getOAuthToken, getFreshAccessToken, listOAuthConnections, deleteOAuthConnection, getUserByOAuthProvider, } from './db';
|
|
7
8
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUserByOAuthProvider = exports.deleteOAuthConnection = exports.listOAuthConnections = exports.getFreshAccessToken = exports.getOAuthToken = exports.upsertOAuthToken = exports.listProviders = exports.getProvider = exports.registerProvider = exports.consumeOAuthState = exports.createOAuthState = exports.setEncryptionKey = exports.getEncryptionKey = exports.decrypt = exports.encrypt = void 0;
|
|
3
|
+
exports.getUserByOAuthProvider = exports.deleteOAuthConnection = exports.listOAuthConnections = exports.getFreshAccessToken = exports.getOAuthToken = exports.upsertOAuthToken = exports.mayProvision = exports.emailDomain = exports.normalizeDomains = exports.listProviders = exports.getProvider = exports.registerProvider = exports.consumeOAuthState = exports.createOAuthState = exports.setEncryptionKey = exports.getEncryptionKey = exports.decrypt = exports.encrypt = void 0;
|
|
4
4
|
exports.initializeOAuth = initializeOAuth;
|
|
5
5
|
const crypto_1 = require("./crypto");
|
|
6
6
|
const providers_1 = require("./providers");
|
|
@@ -17,6 +17,10 @@ var providers_2 = require("./providers");
|
|
|
17
17
|
Object.defineProperty(exports, "registerProvider", { enumerable: true, get: function () { return providers_2.registerProvider; } });
|
|
18
18
|
Object.defineProperty(exports, "getProvider", { enumerable: true, get: function () { return providers_2.getProvider; } });
|
|
19
19
|
Object.defineProperty(exports, "listProviders", { enumerable: true, get: function () { return providers_2.listProviders; } });
|
|
20
|
+
var provisioning_1 = require("./provisioning");
|
|
21
|
+
Object.defineProperty(exports, "normalizeDomains", { enumerable: true, get: function () { return provisioning_1.normalizeDomains; } });
|
|
22
|
+
Object.defineProperty(exports, "emailDomain", { enumerable: true, get: function () { return provisioning_1.emailDomain; } });
|
|
23
|
+
Object.defineProperty(exports, "mayProvision", { enumerable: true, get: function () { return provisioning_1.mayProvision; } });
|
|
20
24
|
var db_1 = require("./db");
|
|
21
25
|
Object.defineProperty(exports, "upsertOAuthToken", { enumerable: true, get: function () { return db_1.upsertOAuthToken; } });
|
|
22
26
|
Object.defineProperty(exports, "getOAuthToken", { enumerable: true, get: function () { return db_1.getOAuthToken; } });
|
|
@@ -74,7 +74,8 @@ function createGitHubHandler(cfg) {
|
|
|
74
74
|
]);
|
|
75
75
|
const user = await userRes.json();
|
|
76
76
|
const emails = await emailRes.json().catch(() => []);
|
|
77
|
-
const
|
|
77
|
+
const verified = emails.filter((e) => e.verified === true);
|
|
78
|
+
const primary = verified.find((e) => e.primary)?.email || verified[0]?.email || null;
|
|
78
79
|
return {
|
|
79
80
|
provider: 'github',
|
|
80
81
|
providerUserId: String(user.id),
|
|
@@ -75,14 +75,14 @@ function createGoogleHandler(cfg) {
|
|
|
75
75
|
};
|
|
76
76
|
},
|
|
77
77
|
async fetchUserInfo(accessToken) {
|
|
78
|
-
const res = await fetch('https://
|
|
78
|
+
const res = await fetch('https://openidconnect.googleapis.com/v1/userinfo', {
|
|
79
79
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
80
80
|
});
|
|
81
81
|
const data = await res.json();
|
|
82
82
|
return {
|
|
83
83
|
provider: 'google',
|
|
84
|
-
providerUserId: data.id,
|
|
85
|
-
email: data.email
|
|
84
|
+
providerUserId: data.sub || data.id,
|
|
85
|
+
email: data.email_verified === true && data.email ? data.email : null,
|
|
86
86
|
displayName: data.name || null,
|
|
87
87
|
raw: data,
|
|
88
88
|
};
|
|
@@ -34,9 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.createMicrosoftHandler = createMicrosoftHandler;
|
|
37
|
+
const MULTI_TENANT_AUTHORITIES = new Set(['common', 'organizations', 'consumers']);
|
|
37
38
|
function createMicrosoftHandler(cfg) {
|
|
38
39
|
const redirectUri = cfg.redirectUri || '';
|
|
39
40
|
const tenantId = process.env.OAUTH_MICROSOFT_TENANT_ID || 'common';
|
|
41
|
+
// Graph does not verify mail or the UPN. Only a single-tenant authority vouches for the account.
|
|
42
|
+
const singleTenant = !MULTI_TENANT_AUTHORITIES.has(tenantId);
|
|
40
43
|
let _ms;
|
|
41
44
|
async function getClient() {
|
|
42
45
|
if (!_ms) {
|
|
@@ -79,7 +82,7 @@ function createMicrosoftHandler(cfg) {
|
|
|
79
82
|
return {
|
|
80
83
|
provider: 'microsoft',
|
|
81
84
|
providerUserId: data.id,
|
|
82
|
-
email: data.mail || data.userPrincipalName || null,
|
|
85
|
+
email: singleTenant ? data.mail || data.userPrincipalName || null : null,
|
|
83
86
|
displayName: data.displayName || null,
|
|
84
87
|
raw: data,
|
|
85
88
|
};
|
|
@@ -66,7 +66,7 @@ function createMockHandler(cfg) {
|
|
|
66
66
|
return {
|
|
67
67
|
provider: 'mock',
|
|
68
68
|
providerUserId: data.sub || data.id || 'mock-user',
|
|
69
|
-
email: data.email
|
|
69
|
+
email: data.email_verified === true && data.email ? data.email : null,
|
|
70
70
|
displayName: data.name || null,
|
|
71
71
|
raw: data,
|
|
72
72
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decides whether an OAuth sign-in may create its own account.
|
|
3
|
+
* Enforced server side in the callback; provider hints are not trusted.
|
|
4
|
+
*/
|
|
5
|
+
export declare function normalizeDomains(domains: string[] | undefined): string[];
|
|
6
|
+
export declare function emailDomain(email: string | null | undefined): string | undefined;
|
|
7
|
+
/** Whether a sign-in with this email may create its own account. Empty list: any. */
|
|
8
|
+
export declare function mayProvision(email: string | null | undefined, allowedDomains: string[]): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Decides whether an OAuth sign-in may create its own account.
|
|
4
|
+
* Enforced server side in the callback; provider hints are not trusted.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.normalizeDomains = normalizeDomains;
|
|
8
|
+
exports.emailDomain = emailDomain;
|
|
9
|
+
exports.mayProvision = mayProvision;
|
|
10
|
+
function normalizeDomains(domains) {
|
|
11
|
+
return (domains ?? []).map((d) => d.trim().toLowerCase().replace(/^@/, '')).filter(Boolean);
|
|
12
|
+
}
|
|
13
|
+
function emailDomain(email) {
|
|
14
|
+
const at = email?.lastIndexOf('@') ?? -1;
|
|
15
|
+
return at > 0 ? email.slice(at + 1).toLowerCase() : undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Whether a sign-in with this email may create its own account. Empty list: any. */
|
|
18
|
+
function mayProvision(email, allowedDomains) {
|
|
19
|
+
if (allowedDomains.length === 0)
|
|
20
|
+
return true;
|
|
21
|
+
const domain = emailDomain(email);
|
|
22
|
+
return domain !== undefined && allowedDomains.includes(domain);
|
|
23
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type RoleScanDone } from './types';
|
|
2
|
+
export declare const SCAN_DONE_RETURN_HOME = "home";
|
|
3
|
+
export declare const SCAN_DONE_AFTER_SECONDS_DEFAULT = 2;
|
|
4
|
+
/** The problem with a `properties.scan_done` value, or null when it is usable (or absent). */
|
|
5
|
+
export declare function scanDoneError(value: unknown): string | null;
|
|
6
|
+
/** The role's return policy from its properties bag, or null when it declares none (or an unusable one). */
|
|
7
|
+
export declare function readScanDone(properties: Record<string, unknown> | null | undefined): RoleScanDone | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SCAN_DONE_AFTER_SECONDS_DEFAULT = exports.SCAN_DONE_RETURN_HOME = void 0;
|
|
4
|
+
exports.scanDoneError = scanDoneError;
|
|
5
|
+
exports.readScanDone = readScanDone;
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
exports.SCAN_DONE_RETURN_HOME = 'home';
|
|
8
|
+
exports.SCAN_DONE_AFTER_SECONDS_DEFAULT = 2;
|
|
9
|
+
const AFTER_SECONDS_MAX = 60;
|
|
10
|
+
/** The problem with a `properties.scan_done` value, or null when it is usable (or absent). */
|
|
11
|
+
function scanDoneError(value) {
|
|
12
|
+
if (value === undefined || value === null)
|
|
13
|
+
return null;
|
|
14
|
+
if (typeof value !== 'object' || Array.isArray(value))
|
|
15
|
+
return 'properties.scan_done must be an object';
|
|
16
|
+
const done = value;
|
|
17
|
+
const known = new Set(['return', 'after_seconds']);
|
|
18
|
+
const extra = Object.keys(done).filter((k) => !known.has(k));
|
|
19
|
+
if (extra.length)
|
|
20
|
+
return `properties.scan_done has unknown key(s): ${extra.join(', ')}`;
|
|
21
|
+
if (typeof done.return !== 'string' || !(done.return === exports.SCAN_DONE_RETURN_HOME || done.return.startsWith('/'))) {
|
|
22
|
+
return `properties.scan_done.return must be '${exports.SCAN_DONE_RETURN_HOME}' or a dashboard-relative route`;
|
|
23
|
+
}
|
|
24
|
+
if (done.after_seconds !== undefined
|
|
25
|
+
&& (!Number.isInteger(done.after_seconds) || done.after_seconds < 0 || done.after_seconds > AFTER_SECONDS_MAX)) {
|
|
26
|
+
return `properties.scan_done.after_seconds must be an integer from 0 to ${AFTER_SECONDS_MAX}`;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/** The role's return policy from its properties bag, or null when it declares none (or an unusable one). */
|
|
31
|
+
function readScanDone(properties) {
|
|
32
|
+
const value = properties?.[types_1.ROLE_PROPERTY_KEYS.SCAN_DONE];
|
|
33
|
+
if (value === undefined || value === null || scanDoneError(value))
|
|
34
|
+
return null;
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
@@ -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 scan_done_1 = require("./scan-done");
|
|
12
13
|
const list_schema_1 = require("../../shared/list-schema");
|
|
13
14
|
const types_1 = require("./types");
|
|
14
15
|
/** Recorded on schema snapshots written by the startup apply. */
|
|
@@ -85,6 +86,9 @@ async function applyRoleConfig(cfg, codeOwned) {
|
|
|
85
86
|
const grantError = (0, badge_grant_1.badgeGrantError)(cfg.properties?.[types_1.ROLE_PROPERTY_KEYS.BADGE_GRANT]);
|
|
86
87
|
if (grantError)
|
|
87
88
|
throw new Error(`role ${cfg.role}: ${grantError}`);
|
|
89
|
+
const scanDoneProblem = (0, scan_done_1.scanDoneError)(cfg.properties?.[types_1.ROLE_PROPERTY_KEYS.SCAN_DONE]);
|
|
90
|
+
if (scanDoneProblem)
|
|
91
|
+
throw new Error(`role ${cfg.role}: ${scanDoneProblem}`);
|
|
88
92
|
const listSchemaError = cfg.list_schema != null ? (0, list_schema_1.listSchemaRelationsError)(cfg.list_schema) : null;
|
|
89
93
|
if (listSchemaError)
|
|
90
94
|
throw new Error(`role ${cfg.role}: list_schema: ${listSchemaError}`);
|
|
@@ -19,6 +19,9 @@ export interface EscalationChain {
|
|
|
19
19
|
* A badge scanned on a device signed in as a member of this role mints
|
|
20
20
|
* its acting grant under this policy instead of the badge scheme's own
|
|
21
21
|
* (see api/scan-codes/badge-policy.ts).
|
|
22
|
+
* - SCAN_DONE: RoleScanDone — where a station locked to this role goes once
|
|
23
|
+
* a scan act completes its row: the kiosk home or a route, after a pause
|
|
24
|
+
* on the done copy.
|
|
22
25
|
* - LINK_VARIABLES: RoleLinkVariable[] — metadata facet names members bind
|
|
23
26
|
* per device. Pins may reference `{lt:name}` as a whole facet value
|
|
24
27
|
* (e.g. `facets={"region":"{lt:region}"}`); the dashboard substitutes
|
|
@@ -32,7 +35,15 @@ export declare const ROLE_PROPERTY_KEYS: {
|
|
|
32
35
|
readonly KIOSK: "kiosk";
|
|
33
36
|
readonly LINK_VARIABLES: "link_variables";
|
|
34
37
|
readonly BADGE_GRANT: "badge_grant";
|
|
38
|
+
readonly SCAN_DONE: "scan_done";
|
|
35
39
|
};
|
|
40
|
+
/** Where a station returns after a scan act completes its row. */
|
|
41
|
+
export interface RoleScanDone {
|
|
42
|
+
/** 'home' is the kiosk home (portal or list); otherwise a dashboard-relative route. */
|
|
43
|
+
return: 'home' | string;
|
|
44
|
+
/** Seconds the done copy stays up first (0-60, default 2). */
|
|
45
|
+
after_seconds?: number;
|
|
46
|
+
}
|
|
36
47
|
/** A station role's badge policy. Absent fields keep the badge scheme's value. */
|
|
37
48
|
export interface RoleBadgeGrant {
|
|
38
49
|
/** How long a badge scan stays primed (1-86400 s). */
|
|
@@ -18,6 +18,9 @@ exports.PORTAL_KEY = exports.PORTAL_LIMITS = exports.ROLE_PROPERTY_KEYS = void 0
|
|
|
18
18
|
* A badge scanned on a device signed in as a member of this role mints
|
|
19
19
|
* its acting grant under this policy instead of the badge scheme's own
|
|
20
20
|
* (see api/scan-codes/badge-policy.ts).
|
|
21
|
+
* - SCAN_DONE: RoleScanDone — where a station locked to this role goes once
|
|
22
|
+
* a scan act completes its row: the kiosk home or a route, after a pause
|
|
23
|
+
* on the done copy.
|
|
21
24
|
* - LINK_VARIABLES: RoleLinkVariable[] — metadata facet names members bind
|
|
22
25
|
* per device. Pins may reference `{lt:name}` as a whole facet value
|
|
23
26
|
* (e.g. `facets={"region":"{lt:region}"}`); the dashboard substitutes
|
|
@@ -31,6 +34,7 @@ exports.ROLE_PROPERTY_KEYS = {
|
|
|
31
34
|
KIOSK: 'kiosk',
|
|
32
35
|
LINK_VARIABLES: 'link_variables',
|
|
33
36
|
BADGE_GRANT: 'badge_grant',
|
|
37
|
+
SCAN_DONE: 'scan_done',
|
|
34
38
|
};
|
|
35
39
|
/** Bounds for a role's portals: how many, and the matrix of each (rows of cells, each cell a pin). */
|
|
36
40
|
exports.PORTAL_LIMITS = {
|
|
@@ -151,8 +151,57 @@ function assertValidChoices(choices, at) {
|
|
|
151
151
|
throw new Error(`${cat}: duplicate code "${choice.code}"`);
|
|
152
152
|
codes.add(choice.code);
|
|
153
153
|
}
|
|
154
|
+
if (choice.done !== undefined) {
|
|
155
|
+
if (!choice.done || typeof choice.done !== 'object' || typeof choice.done.markdown !== 'string' || !choice.done.markdown) {
|
|
156
|
+
throw new Error(`${cat}: done.markdown is required`);
|
|
157
|
+
}
|
|
158
|
+
if (!types_1.SCAN_MUTATING_VERBS.includes(choice.verb)) {
|
|
159
|
+
throw new Error(`${cat}: done applies only to choices that write`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (choice.hidden !== undefined) {
|
|
163
|
+
if (typeof choice.hidden !== 'boolean')
|
|
164
|
+
throw new Error(`${cat}: hidden must be a boolean`);
|
|
165
|
+
if (choice.hidden && !choice.roles?.length)
|
|
166
|
+
throw new Error(`${cat}: hidden requires roles`);
|
|
167
|
+
}
|
|
168
|
+
if (choice.when !== undefined)
|
|
169
|
+
assertValidWhen(choice.when, cat);
|
|
154
170
|
});
|
|
155
171
|
}
|
|
172
|
+
/** A choice's `when`: facet keys to scalar values the row must carry. */
|
|
173
|
+
function assertValidWhen(when, at) {
|
|
174
|
+
if (!when || typeof when !== 'object' || Array.isArray(when) || Object.keys(when).length === 0) {
|
|
175
|
+
throw new Error(`${at}: when must be a non-empty object of facet values`);
|
|
176
|
+
}
|
|
177
|
+
for (const [key, value] of Object.entries(when)) {
|
|
178
|
+
if (!facet_sql_1.FACET_KEY.test(key))
|
|
179
|
+
throw new Error(`${at}: when key "${key}" is not a facet key`);
|
|
180
|
+
if (!['string', 'number', 'boolean'].includes(typeof value)) {
|
|
181
|
+
throw new Error(`${at}: when.${key} must be a string, number, or boolean`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** A step's `follow`: the roles the subject's next row may be in, and how long to wait for it. */
|
|
186
|
+
function assertValidFollow(step, at) {
|
|
187
|
+
const follow = step.follow;
|
|
188
|
+
if (follow === undefined)
|
|
189
|
+
return;
|
|
190
|
+
if (!follow || typeof follow !== 'object' || Array.isArray(follow))
|
|
191
|
+
throw new Error(`${at}: follow must be an object`);
|
|
192
|
+
if (!Array.isArray(follow.roles) || follow.roles.length === 0
|
|
193
|
+
|| follow.roles.some((r) => typeof r !== 'string' || !r)) {
|
|
194
|
+
throw new Error(`${at}: follow.roles must be a non-empty array of role names`);
|
|
195
|
+
}
|
|
196
|
+
if (follow.waitSeconds !== undefined
|
|
197
|
+
&& (!Number.isInteger(follow.waitSeconds) || follow.waitSeconds < 1 || follow.waitSeconds > types_1.SCAN_FOLLOW_WAIT_MAX_SECONDS)) {
|
|
198
|
+
throw new Error(`${at}: follow.waitSeconds must be an integer from 1 to ${types_1.SCAN_FOLLOW_WAIT_MAX_SECONDS}`);
|
|
199
|
+
}
|
|
200
|
+
if (!types_1.SCAN_MUTATING_VERBS.includes(step.verb))
|
|
201
|
+
throw new Error(`${at}: follow applies only to steps that write`);
|
|
202
|
+
if (!step.subject)
|
|
203
|
+
throw new Error(`${at}: follow applies only to steps that act on the held subject`);
|
|
204
|
+
}
|
|
156
205
|
/**
|
|
157
206
|
* Reject incoherent rule steps at write time: a rule that can never
|
|
158
207
|
* execute its verb must fail the upsert, not the factory-floor scan.
|
|
@@ -247,6 +296,7 @@ function assertValidSteps(steps) {
|
|
|
247
296
|
throw new Error(`${at}: done applies only to steps that write`);
|
|
248
297
|
}
|
|
249
298
|
}
|
|
299
|
+
assertValidFollow(step, at);
|
|
250
300
|
assertValidTemplateTokens(step, at);
|
|
251
301
|
if (step.query && step.query.roles && !Array.isArray(step.query.roles)) {
|
|
252
302
|
throw new Error(`${at}: query.roles must be an array`);
|
package/build/start/config.js
CHANGED
|
@@ -98,6 +98,7 @@ async function applyServerAuthConfig(startConfig) {
|
|
|
98
98
|
autoProvision: startConfig.auth.oauth.autoProvision,
|
|
99
99
|
defaultRoleType: startConfig.auth.oauth.defaultRoleType,
|
|
100
100
|
baseUrl: startConfig.auth.oauth.baseUrl,
|
|
101
|
+
allowedDomains: startConfig.auth.oauth.allowedDomains,
|
|
101
102
|
});
|
|
102
103
|
}
|
|
103
104
|
const oauthServer = startConfig.auth?.oauthServer
|