@leaflow/sdk 0.186.0 → 0.187.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/fleet/v1/generated/functions.d.ts +1710 -0
- package/dist/fleet/v1/generated/functions.js +1655 -0
- package/dist/fleet/v1/generated/models.d.ts +1534 -0
- package/dist/fleet/v1/generated/models.js +97 -0
- package/dist/fleet/v1/generated/schemas.zod.d.ts +1172 -0
- package/dist/fleet/v1/generated/schemas.zod.js +1291 -0
- package/dist/fleet/v1/generated/validators/accountList.zod.d.ts +250 -0
- package/dist/fleet/v1/generated/validators/accountList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/accountResource.zod.d.ts +244 -0
- package/dist/fleet/v1/generated/validators/accountResource.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/approveEnrollmentRequest.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/approveEnrollmentRequest.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/callMcpToolRequest.zod.d.ts +234 -0
- package/dist/fleet/v1/generated/validators/callMcpToolRequest.zod.js +240 -0
- package/dist/fleet/v1/generated/validators/callMcpToolResponse.zod.d.ts +231 -0
- package/dist/fleet/v1/generated/validators/callMcpToolResponse.zod.js +231 -0
- package/dist/fleet/v1/generated/validators/createGroupMemberRequest.zod.d.ts +231 -0
- package/dist/fleet/v1/generated/validators/createGroupMemberRequest.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/createGroupRequest.zod.d.ts +231 -0
- package/dist/fleet/v1/generated/validators/createGroupRequest.zod.js +230 -0
- package/dist/fleet/v1/generated/validators/createMachineRegistrationRequest.zod.d.ts +236 -0
- package/dist/fleet/v1/generated/validators/createMachineRegistrationRequest.zod.js +243 -0
- package/dist/fleet/v1/generated/validators/createMachineRegistrationResponse.zod.d.ts +247 -0
- package/dist/fleet/v1/generated/validators/createMachineRegistrationResponse.zod.js +233 -0
- package/dist/fleet/v1/generated/validators/createParticipantRequest.zod.d.ts +248 -0
- package/dist/fleet/v1/generated/validators/createParticipantRequest.zod.js +261 -0
- package/dist/fleet/v1/generated/validators/createParticipantResponse.zod.d.ts +277 -0
- package/dist/fleet/v1/generated/validators/createParticipantResponse.zod.js +241 -0
- package/dist/fleet/v1/generated/validators/createPeerConnectionCandidatesRequest.zod.d.ts +236 -0
- package/dist/fleet/v1/generated/validators/createPeerConnectionCandidatesRequest.zod.js +238 -0
- package/dist/fleet/v1/generated/validators/createPeerConnectionRequest.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/createPeerConnectionRequest.zod.js +233 -0
- package/dist/fleet/v1/generated/validators/createSessionRequest.zod.d.ts +240 -0
- package/dist/fleet/v1/generated/validators/createSessionRequest.zod.js +231 -0
- package/dist/fleet/v1/generated/validators/cursorPagination.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/cursorPagination.zod.js +232 -0
- package/dist/fleet/v1/generated/validators/deleteMcpServerParams.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/deleteMcpServerParams.zod.js +230 -0
- package/dist/fleet/v1/generated/validators/desktopOptions.zod.d.ts +242 -0
- package/dist/fleet/v1/generated/validators/desktopOptions.zod.js +254 -0
- package/dist/fleet/v1/generated/validators/desktopState.zod.d.ts +235 -0
- package/dist/fleet/v1/generated/validators/desktopState.zod.js +231 -0
- package/dist/fleet/v1/generated/validators/directoryName.zod.d.ts +231 -0
- package/dist/fleet/v1/generated/validators/directoryName.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/enrollmentResource.zod.d.ts +243 -0
- package/dist/fleet/v1/generated/validators/enrollmentResource.zod.js +241 -0
- package/dist/fleet/v1/generated/validators/enrollmentState.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/enrollmentState.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/error.zod.d.ts +243 -0
- package/dist/fleet/v1/generated/validators/error.zod.js +232 -0
- package/dist/fleet/v1/generated/validators/errorStatus.zod.d.ts +241 -0
- package/dist/fleet/v1/generated/validators/errorStatus.zod.js +256 -0
- package/dist/fleet/v1/generated/validators/featureState.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/featureState.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/fieldViolation.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/fieldViolation.zod.js +235 -0
- package/dist/fleet/v1/generated/validators/findEnrollmentByPairingCodeParams.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/findEnrollmentByPairingCodeParams.zod.js +230 -0
- package/dist/fleet/v1/generated/validators/findEnrollmentResponse.zod.d.ts +245 -0
- package/dist/fleet/v1/generated/validators/findEnrollmentResponse.zod.js +232 -0
- package/dist/fleet/v1/generated/validators/groupList.zod.d.ts +242 -0
- package/dist/fleet/v1/generated/validators/groupList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/groupResource.zod.d.ts +237 -0
- package/dist/fleet/v1/generated/validators/groupResource.zod.js +235 -0
- package/dist/fleet/v1/generated/validators/iceCandidate.zod.d.ts +234 -0
- package/dist/fleet/v1/generated/validators/iceCandidate.zod.js +241 -0
- package/dist/fleet/v1/generated/validators/iceServer.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/iceServer.zod.js +236 -0
- package/dist/fleet/v1/generated/validators/listAccountsParams.zod.d.ts +239 -0
- package/dist/fleet/v1/generated/validators/listAccountsParams.zod.js +241 -0
- package/dist/fleet/v1/generated/validators/listGroupMembersParams.zod.d.ts +236 -0
- package/dist/fleet/v1/generated/validators/listGroupMembersParams.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/listGroupsParams.zod.d.ts +236 -0
- package/dist/fleet/v1/generated/validators/listGroupsParams.zod.js +238 -0
- package/dist/fleet/v1/generated/validators/listMachineEventsParams.zod.d.ts +240 -0
- package/dist/fleet/v1/generated/validators/listMachineEventsParams.zod.js +244 -0
- package/dist/fleet/v1/generated/validators/listMachineRegistrationsParams.zod.d.ts +236 -0
- package/dist/fleet/v1/generated/validators/listMachineRegistrationsParams.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/listMachinesParams.zod.d.ts +238 -0
- package/dist/fleet/v1/generated/validators/listMachinesParams.zod.js +240 -0
- package/dist/fleet/v1/generated/validators/listMcpToolsParams.zod.d.ts +239 -0
- package/dist/fleet/v1/generated/validators/listMcpToolsParams.zod.js +241 -0
- package/dist/fleet/v1/generated/validators/listPrivilegeAutoApprovalsParams.zod.d.ts +236 -0
- package/dist/fleet/v1/generated/validators/listPrivilegeAutoApprovalsParams.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/listPrivilegeRequestsParams.zod.d.ts +244 -0
- package/dist/fleet/v1/generated/validators/listPrivilegeRequestsParams.zod.js +245 -0
- package/dist/fleet/v1/generated/validators/listSessionsParams.zod.d.ts +240 -0
- package/dist/fleet/v1/generated/validators/listSessionsParams.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/machineEventList.zod.d.ts +244 -0
- package/dist/fleet/v1/generated/validators/machineEventList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/machineEventResource.zod.d.ts +238 -0
- package/dist/fleet/v1/generated/validators/machineEventResource.zod.js +238 -0
- package/dist/fleet/v1/generated/validators/machineEventType.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/machineEventType.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/machineFeature.zod.d.ts +237 -0
- package/dist/fleet/v1/generated/validators/machineFeature.zod.js +239 -0
- package/dist/fleet/v1/generated/validators/machineList.zod.d.ts +261 -0
- package/dist/fleet/v1/generated/validators/machineList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/machineRegistrationList.zod.d.ts +250 -0
- package/dist/fleet/v1/generated/validators/machineRegistrationList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/machineRegistrationResource.zod.d.ts +244 -0
- package/dist/fleet/v1/generated/validators/machineRegistrationResource.zod.js +249 -0
- package/dist/fleet/v1/generated/validators/machineRegistrationState.zod.d.ts +234 -0
- package/dist/fleet/v1/generated/validators/machineRegistrationState.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/machineResource.zod.d.ts +256 -0
- package/dist/fleet/v1/generated/validators/machineResource.zod.js +257 -0
- package/dist/fleet/v1/generated/validators/mcpConfigurationFile.zod.d.ts +240 -0
- package/dist/fleet/v1/generated/validators/mcpConfigurationFile.zod.js +246 -0
- package/dist/fleet/v1/generated/validators/mcpConfigurationResource.zod.d.ts +279 -0
- package/dist/fleet/v1/generated/validators/mcpConfigurationResource.zod.js +232 -0
- package/dist/fleet/v1/generated/validators/mcpImplementation.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/mcpImplementation.zod.js +231 -0
- package/dist/fleet/v1/generated/validators/mcpServerFailure.zod.d.ts +237 -0
- package/dist/fleet/v1/generated/validators/mcpServerFailure.zod.js +237 -0
- package/dist/fleet/v1/generated/validators/mcpServerResource.zod.d.ts +265 -0
- package/dist/fleet/v1/generated/validators/mcpServerResource.zod.js +256 -0
- package/dist/fleet/v1/generated/validators/mcpToolList.zod.d.ts +252 -0
- package/dist/fleet/v1/generated/validators/mcpToolList.zod.js +235 -0
- package/dist/fleet/v1/generated/validators/mcpToolResource.zod.d.ts +237 -0
- package/dist/fleet/v1/generated/validators/mcpToolResource.zod.js +243 -0
- package/dist/fleet/v1/generated/validators/mcpTransport.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/mcpTransport.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/mcpUnavailableServer.zod.d.ts +240 -0
- package/dist/fleet/v1/generated/validators/mcpUnavailableServer.zod.js +231 -0
- package/dist/fleet/v1/generated/validators/migrationStep.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/migrationStep.zod.js +233 -0
- package/dist/fleet/v1/generated/validators/namedIdentity.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/namedIdentity.zod.js +233 -0
- package/dist/fleet/v1/generated/validators/offsetPagination.zod.d.ts +234 -0
- package/dist/fleet/v1/generated/validators/offsetPagination.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/operatingSystem.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/operatingSystem.zod.js +233 -0
- package/dist/fleet/v1/generated/validators/participantList.zod.d.ts +242 -0
- package/dist/fleet/v1/generated/validators/participantList.zod.js +230 -0
- package/dist/fleet/v1/generated/validators/participantResource.zod.d.ts +240 -0
- package/dist/fleet/v1/generated/validators/participantResource.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/peerConnection.zod.d.ts +241 -0
- package/dist/fleet/v1/generated/validators/peerConnection.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/privilegeAutoApprovalList.zod.d.ts +241 -0
- package/dist/fleet/v1/generated/validators/privilegeAutoApprovalList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/privilegeAutoApprovalResource.zod.d.ts +235 -0
- package/dist/fleet/v1/generated/validators/privilegeAutoApprovalResource.zod.js +236 -0
- package/dist/fleet/v1/generated/validators/privilegeDecider.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/privilegeDecider.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/privilegeRequestList.zod.d.ts +258 -0
- package/dist/fleet/v1/generated/validators/privilegeRequestList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/privilegeRequestResource.zod.d.ts +253 -0
- package/dist/fleet/v1/generated/validators/privilegeRequestResource.zod.js +255 -0
- package/dist/fleet/v1/generated/validators/privilegeRequestState.zod.d.ts +235 -0
- package/dist/fleet/v1/generated/validators/privilegeRequestState.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/publicKey.zod.d.ts +230 -0
- package/dist/fleet/v1/generated/validators/publicKey.zod.js +231 -0
- package/dist/fleet/v1/generated/validators/renewParticipantRequest.zod.d.ts +236 -0
- package/dist/fleet/v1/generated/validators/renewParticipantRequest.zod.js +235 -0
- package/dist/fleet/v1/generated/validators/renewParticipantResponse.zod.d.ts +257 -0
- package/dist/fleet/v1/generated/validators/renewParticipantResponse.zod.js +238 -0
- package/dist/fleet/v1/generated/validators/replaceMcpConfigurationRequest.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/replaceMcpConfigurationRequest.zod.js +237 -0
- package/dist/fleet/v1/generated/validators/rtcConfiguration.zod.d.ts +240 -0
- package/dist/fleet/v1/generated/validators/rtcConfiguration.zod.js +236 -0
- package/dist/fleet/v1/generated/validators/runCommandRequest.zod.d.ts +235 -0
- package/dist/fleet/v1/generated/validators/runCommandRequest.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/runCommandResponse.zod.d.ts +237 -0
- package/dist/fleet/v1/generated/validators/runCommandResponse.zod.js +245 -0
- package/dist/fleet/v1/generated/validators/sendMcpRequestRequest.zod.d.ts +234 -0
- package/dist/fleet/v1/generated/validators/sendMcpRequestRequest.zod.js +239 -0
- package/dist/fleet/v1/generated/validators/sendMcpRequestResponse.zod.d.ts +231 -0
- package/dist/fleet/v1/generated/validators/sendMcpRequestResponse.zod.js +231 -0
- package/dist/fleet/v1/generated/validators/sessionCloseReason.zod.d.ts +242 -0
- package/dist/fleet/v1/generated/validators/sessionCloseReason.zod.js +242 -0
- package/dist/fleet/v1/generated/validators/sessionList.zod.d.ts +274 -0
- package/dist/fleet/v1/generated/validators/sessionList.zod.js +234 -0
- package/dist/fleet/v1/generated/validators/sessionMode.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/sessionMode.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/sessionResource.zod.d.ts +268 -0
- package/dist/fleet/v1/generated/validators/sessionResource.zod.js +254 -0
- package/dist/fleet/v1/generated/validators/sessionState.zod.d.ts +234 -0
- package/dist/fleet/v1/generated/validators/sessionState.zod.js +229 -0
- package/dist/fleet/v1/generated/validators/signedMessage.zod.d.ts +233 -0
- package/dist/fleet/v1/generated/validators/signedMessage.zod.js +235 -0
- package/dist/fleet/v1/generated/validators/signingKey.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/signingKey.zod.js +233 -0
- package/dist/fleet/v1/generated/validators/updateAccountRequest.zod.d.ts +235 -0
- package/dist/fleet/v1/generated/validators/updateAccountRequest.zod.js +240 -0
- package/dist/fleet/v1/generated/validators/updateGroupRequest.zod.d.ts +231 -0
- package/dist/fleet/v1/generated/validators/updateGroupRequest.zod.js +230 -0
- package/dist/fleet/v1/generated/validators/updateMachineRequest.zod.d.ts +232 -0
- package/dist/fleet/v1/generated/validators/updateMachineRequest.zod.js +230 -0
- package/dist/fleet/v1/generated/validators/updateMcpServerRequest.zod.d.ts +254 -0
- package/dist/fleet/v1/generated/validators/updateMcpServerRequest.zod.js +282 -0
- package/dist/fleet/v1/generated/validators/updateMcpServerResponse.zod.d.ts +279 -0
- package/dist/fleet/v1/generated/validators/updateMcpServerResponse.zod.js +232 -0
- package/dist/fleet/v1/generated/validators/updatePrivilegeAutoApprovalRequest.zod.d.ts +231 -0
- package/dist/fleet/v1/generated/validators/updatePrivilegeAutoApprovalRequest.zod.js +232 -0
- package/dist/fleet/v1/index.d.ts +3 -0
- package/dist/fleet/v1/index.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/proto/google/rpc/status_pb.d.ts +48 -0
- package/dist/proto/google/rpc/status_pb.js +24 -0
- package/dist/proto/leaflow/fleet/audio/v1/audio_pb.d.ts +262 -0
- package/dist/proto/leaflow/fleet/audio/v1/audio_pb.js +51 -0
- package/dist/proto/leaflow/fleet/camera/v1/camera_pb.d.ts +265 -0
- package/dist/proto/leaflow/fleet/camera/v1/camera_pb.js +70 -0
- package/dist/proto/leaflow/fleet/command/v1/command_pb.d.ts +158 -0
- package/dist/proto/leaflow/fleet/command/v1/command_pb.js +25 -0
- package/dist/proto/leaflow/fleet/control/v1/control_pb.d.ts +1226 -0
- package/dist/proto/leaflow/fleet/control/v1/control_pb.js +354 -0
- package/dist/proto/leaflow/fleet/device/v1/device_pb.d.ts +422 -0
- package/dist/proto/leaflow/fleet/device/v1/device_pb.js +183 -0
- package/dist/proto/leaflow/fleet/directory/v1/directory_pb.d.ts +429 -0
- package/dist/proto/leaflow/fleet/directory/v1/directory_pb.js +78 -0
- package/dist/proto/leaflow/fleet/exec/v1/exec_pb.d.ts +287 -0
- package/dist/proto/leaflow/fleet/exec/v1/exec_pb.js +78 -0
- package/dist/proto/leaflow/fleet/filetransfer/v1/filetransfer_pb.d.ts +731 -0
- package/dist/proto/leaflow/fleet/filetransfer/v1/filetransfer_pb.js +163 -0
- package/dist/proto/leaflow/fleet/gamepad/v1/gamepad_pb.d.ts +347 -0
- package/dist/proto/leaflow/fleet/gamepad/v1/gamepad_pb.js +124 -0
- package/dist/proto/leaflow/fleet/host/v1/host_pb.d.ts +619 -0
- package/dist/proto/leaflow/fleet/host/v1/host_pb.js +206 -0
- package/dist/proto/leaflow/fleet/logs/v1/logs_pb.d.ts +293 -0
- package/dist/proto/leaflow/fleet/logs/v1/logs_pb.js +90 -0
- package/dist/proto/leaflow/fleet/machine/v1/machine_pb.d.ts +448 -0
- package/dist/proto/leaflow/fleet/machine/v1/machine_pb.js +157 -0
- package/dist/proto/leaflow/fleet/mcp/v1/mcp_pb.d.ts +891 -0
- package/dist/proto/leaflow/fleet/mcp/v1/mcp_pb.js +306 -0
- package/dist/proto/leaflow/fleet/portforward/v1/portforward_pb.d.ts +688 -0
- package/dist/proto/leaflow/fleet/portforward/v1/portforward_pb.js +209 -0
- package/dist/proto/leaflow/fleet/printing/v1/printing_pb.d.ts +741 -0
- package/dist/proto/leaflow/fleet/printing/v1/printing_pb.js +260 -0
- package/dist/proto/leaflow/fleet/privilege/v1/privilege_pb.d.ts +569 -0
- package/dist/proto/leaflow/fleet/privilege/v1/privilege_pb.js +168 -0
- package/dist/proto/leaflow/fleet/rpc/v1/rpc_pb.d.ts +234 -0
- package/dist/proto/leaflow/fleet/rpc/v1/rpc_pb.js +70 -0
- package/dist/proto/leaflow/fleet/session/v1/session_pb.d.ts +411 -0
- package/dist/proto/leaflow/fleet/session/v1/session_pb.js +130 -0
- package/dist/proto/leaflow/fleet/sshagent/v1/sshagent_pb.d.ts +163 -0
- package/dist/proto/leaflow/fleet/sshagent/v1/sshagent_pb.js +64 -0
- package/dist/proto/leaflow/fleet/terminal/v1/terminal_pb.d.ts +297 -0
- package/dist/proto/leaflow/fleet/terminal/v1/terminal_pb.js +54 -0
- package/dist/proto/leaflow/fleet/transport/v1/transport_pb.d.ts +1055 -0
- package/dist/proto/leaflow/fleet/transport/v1/transport_pb.js +251 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/accessibility/v1/accessibility_pb.d.ts +1298 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/accessibility/v1/accessibility_pb.js +437 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/application/v1/application_pb.d.ts +888 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/application/v1/application_pb.js +210 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/capture/v1/capture_pb.d.ts +231 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/capture/v1/capture_pb.js +63 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/change/v1/change_pb.d.ts +965 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/change/v1/change_pb.js +239 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/cursor/v1/cursor_pb.d.ts +201 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/cursor/v1/cursor_pb.js +34 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/datatransfer/v1/datatransfer_pb.d.ts +1489 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/datatransfer/v1/datatransfer_pb.js +256 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/display/v1/display_pb.d.ts +380 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/display/v1/display_pb.js +89 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/draw/v1/draw_pb.d.ts +587 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/draw/v1/draw_pb.js +139 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/host/v1/host_pb.d.ts +69 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/host/v1/host_pb.js +19 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/input/v1/input_pb.d.ts +1463 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/input/v1/input_pb.js +321 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/lease/v1/lease_pb.d.ts +93 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/lease/v1/lease_pb.js +24 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/notification/v1/notification_pb.d.ts +414 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/notification/v1/notification_pb.js +137 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/tray/v1/tray_pb.d.ts +928 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/tray/v1/tray_pb.js +413 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/window/v1/window_pb.d.ts +1559 -0
- package/dist/proto/leaflow/fleet/virtualdesktop/window/v1/window_pb.js +664 -0
- package/dist/routes.d.ts +440 -0
- package/dist/routes.js +495 -0
- package/package.json +11 -3
|
@@ -0,0 +1,1655 @@
|
|
|
1
|
+
export const getListMachinesUrl = (params) => {
|
|
2
|
+
const normalizedParams = new URLSearchParams();
|
|
3
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
4
|
+
if (value !== undefined) {
|
|
5
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
const stringifiedParams = normalizedParams.toString();
|
|
9
|
+
return stringifiedParams.length > 0
|
|
10
|
+
? `https://fleet.leaflow.cloud/api/v1/machines?${stringifiedParams}`
|
|
11
|
+
: `https://fleet.leaflow.cloud/api/v1/machines`;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Returns the machines of the current project, newest first.
|
|
15
|
+
* @summary List machines
|
|
16
|
+
*/
|
|
17
|
+
export const listMachines = async (params, options, fetchFn) => {
|
|
18
|
+
const res = await (fetchFn ?? fetch)(getListMachinesUrl(params), {
|
|
19
|
+
...options,
|
|
20
|
+
method: "GET",
|
|
21
|
+
});
|
|
22
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
23
|
+
const data = body ? JSON.parse(body) : {};
|
|
24
|
+
return { data, status: res.status, headers: res.headers };
|
|
25
|
+
};
|
|
26
|
+
export const getGetMachineUrl = (machineId) => {
|
|
27
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}`;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* @summary Get a machine
|
|
31
|
+
*/
|
|
32
|
+
export const getMachine = async (machineId, options, fetchFn) => {
|
|
33
|
+
const res = await (fetchFn ?? fetch)(getGetMachineUrl(machineId), {
|
|
34
|
+
...options,
|
|
35
|
+
method: "GET",
|
|
36
|
+
});
|
|
37
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
38
|
+
const data = body ? JSON.parse(body) : {};
|
|
39
|
+
return { data, status: res.status, headers: res.headers };
|
|
40
|
+
};
|
|
41
|
+
export const getUpdateMachineUrl = (machineId) => {
|
|
42
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}`;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Changes the machine's name. Requires `fleet:machines.manage`.
|
|
46
|
+
* @summary Update a machine
|
|
47
|
+
*/
|
|
48
|
+
export const updateMachine = async (machineId, updateMachineRequest, options, fetchFn) => {
|
|
49
|
+
const getHeaders = (h) => {
|
|
50
|
+
if (!h)
|
|
51
|
+
return {};
|
|
52
|
+
if (h instanceof Headers)
|
|
53
|
+
return Object.fromEntries(h.entries());
|
|
54
|
+
if (Symbol.iterator in h) {
|
|
55
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
56
|
+
}
|
|
57
|
+
const headers = {};
|
|
58
|
+
for (const [name, value] of Object.entries(h)) {
|
|
59
|
+
if (value !== undefined)
|
|
60
|
+
headers[name] = value;
|
|
61
|
+
}
|
|
62
|
+
return headers;
|
|
63
|
+
};
|
|
64
|
+
const res = await (fetchFn ?? fetch)(getUpdateMachineUrl(machineId), {
|
|
65
|
+
...options,
|
|
66
|
+
method: "PATCH",
|
|
67
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
68
|
+
body: JSON.stringify(updateMachineRequest),
|
|
69
|
+
});
|
|
70
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
71
|
+
const data = body ? JSON.parse(body) : {};
|
|
72
|
+
return { data, status: res.status, headers: res.headers };
|
|
73
|
+
};
|
|
74
|
+
export const getDeleteMachineUrl = (machineId) => {
|
|
75
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}`;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Removes the machine from the project. Every participant of its sessions is disconnected at
|
|
79
|
+
* once and the Agent is refused from then on; to use the machine again, enroll it again.
|
|
80
|
+
* Sessions still open on the machine can no longer be reached and end according to their own
|
|
81
|
+
* timeouts. Nothing on the machine is deleted.
|
|
82
|
+
*
|
|
83
|
+
* Requires `fleet:machines.manage`.
|
|
84
|
+
* @summary Remove a machine
|
|
85
|
+
*/
|
|
86
|
+
export const deleteMachine = async (machineId, options, fetchFn) => {
|
|
87
|
+
const res = await (fetchFn ?? fetch)(getDeleteMachineUrl(machineId), {
|
|
88
|
+
...options,
|
|
89
|
+
method: "DELETE",
|
|
90
|
+
});
|
|
91
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
92
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
93
|
+
return { data, status: res.status, headers: res.headers };
|
|
94
|
+
};
|
|
95
|
+
export const getListMachineEventsUrl = (machineId, params) => {
|
|
96
|
+
const normalizedParams = new URLSearchParams();
|
|
97
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
98
|
+
if (value !== undefined) {
|
|
99
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
const stringifiedParams = normalizedParams.toString();
|
|
103
|
+
return stringifiedParams.length > 0
|
|
104
|
+
? `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/events?${stringifiedParams}`
|
|
105
|
+
: `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/events`;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Returns what the machine reported about itself, newest first, such as a directory account
|
|
109
|
+
* it does not serve because a local account uses its name. Events are kept for 30 days.
|
|
110
|
+
* @summary List the events of a machine
|
|
111
|
+
*/
|
|
112
|
+
export const listMachineEvents = async (machineId, params, options, fetchFn) => {
|
|
113
|
+
const res = await (fetchFn ?? fetch)(getListMachineEventsUrl(machineId, params), {
|
|
114
|
+
...options,
|
|
115
|
+
method: "GET",
|
|
116
|
+
});
|
|
117
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
118
|
+
const data = body ? JSON.parse(body) : {};
|
|
119
|
+
return { data, status: res.status, headers: res.headers };
|
|
120
|
+
};
|
|
121
|
+
export const getRunMachineCommandUrl = (machineId) => {
|
|
122
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}:runCommand`;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Runs one command line on the machine as the caller's account, with its login shell, and
|
|
126
|
+
* returns once it exited or was killed, with its exit status and what it wrote. Pipes,
|
|
127
|
+
* redirection and `&&` work; there is no terminal and no standard input. The machine admits
|
|
128
|
+
* the account through PAM as for a login. The account is created if the caller has none yet.
|
|
129
|
+
* A command that fails is still a successful request: its exit status is its result.
|
|
130
|
+
*
|
|
131
|
+
* Inside the command, `sudo` works without a prompt while the caller has
|
|
132
|
+
* `fleet:machines.admin` on the machine, and refuses otherwise.
|
|
133
|
+
*
|
|
134
|
+
* The request is held until the command ends, at most `timeout_seconds` and a few seconds
|
|
135
|
+
* more. Neither the command nor its output is hidden from the platform: do not put secrets
|
|
136
|
+
* into either.
|
|
137
|
+
*
|
|
138
|
+
* Requires `fleet:machines.login` on the machine.
|
|
139
|
+
*
|
|
140
|
+
* Fails with:
|
|
141
|
+
* - `MACHINE_OFFLINE` when the machine is not connected and does not connect again in time;
|
|
142
|
+
* - `FEATURE_UNAVAILABLE` when the machine does not offer `leaflow.fleet.command.v1`;
|
|
143
|
+
* - `USER_NOT_FOUND`, `USER_NOT_ALLOWED`, `ACCOUNT_EXPIRED` or `PAM_PERMISSION_DENIED` when
|
|
144
|
+
* the machine refuses the account, as for opening a session;
|
|
145
|
+
* - `COMMAND_START_FAILED` when the shell could not start; nothing ran;
|
|
146
|
+
* - `COMMAND_LOST` when the machine lost the command while it ran. The command may have run
|
|
147
|
+
* in part, and its output is lost;
|
|
148
|
+
* - `MACHINE_TIMEOUT` when the machine did not answer in time. The command may have run.
|
|
149
|
+
* @summary Run a command
|
|
150
|
+
*/
|
|
151
|
+
export const runMachineCommand = async (machineId, runCommandRequest, options, fetchFn) => {
|
|
152
|
+
const getHeaders = (h) => {
|
|
153
|
+
if (!h)
|
|
154
|
+
return {};
|
|
155
|
+
if (h instanceof Headers)
|
|
156
|
+
return Object.fromEntries(h.entries());
|
|
157
|
+
if (Symbol.iterator in h) {
|
|
158
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
159
|
+
}
|
|
160
|
+
const headers = {};
|
|
161
|
+
for (const [name, value] of Object.entries(h)) {
|
|
162
|
+
if (value !== undefined)
|
|
163
|
+
headers[name] = value;
|
|
164
|
+
}
|
|
165
|
+
return headers;
|
|
166
|
+
};
|
|
167
|
+
const res = await (fetchFn ?? fetch)(getRunMachineCommandUrl(machineId), {
|
|
168
|
+
...options,
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
171
|
+
body: JSON.stringify(runCommandRequest),
|
|
172
|
+
});
|
|
173
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
174
|
+
const data = body ? JSON.parse(body) : {};
|
|
175
|
+
return { data, status: res.status, headers: res.headers };
|
|
176
|
+
};
|
|
177
|
+
export const getGetMcpConfigurationUrl = (machineId) => {
|
|
178
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-configuration`;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Returns the caller's MCP configuration file on the machine and every server in it, with
|
|
182
|
+
* what each is doing now. The values of `env` and `headers` are never returned, only their
|
|
183
|
+
* keys. Requires `fleet:machines.login` on the machine.
|
|
184
|
+
*
|
|
185
|
+
* Fails with:
|
|
186
|
+
* - `MACHINE_OFFLINE` when the machine is not connected and does not connect again in time;
|
|
187
|
+
* - `FEATURE_UNAVAILABLE` when the machine does not offer `leaflow.fleet.mcp.v1`;
|
|
188
|
+
* - `USER_NOT_FOUND`, `USER_NOT_ALLOWED`, `ACCOUNT_EXPIRED` or `PAM_PERMISSION_DENIED` when
|
|
189
|
+
* the machine refuses the account, as for opening a session;
|
|
190
|
+
* - `MACHINE_TIMEOUT` when the machine did not answer in time.
|
|
191
|
+
* @summary Get the caller's MCP configuration on a machine
|
|
192
|
+
*/
|
|
193
|
+
export const getMcpConfiguration = async (machineId, options, fetchFn) => {
|
|
194
|
+
const res = await (fetchFn ?? fetch)(getGetMcpConfigurationUrl(machineId), {
|
|
195
|
+
...options,
|
|
196
|
+
method: "GET",
|
|
197
|
+
});
|
|
198
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
199
|
+
const data = body ? JSON.parse(body) : {};
|
|
200
|
+
return { data, status: res.status, headers: res.headers };
|
|
201
|
+
};
|
|
202
|
+
export const getReplaceMcpConfigurationUrl = (machineId) => {
|
|
203
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-configuration`;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Replaces the caller's MCP configuration file on the machine as a whole, also one that cannot
|
|
207
|
+
* be read or is not valid. The machine starts the servers that were added, stops the ones
|
|
208
|
+
* that were removed and restarts the ones that changed when they are next used. The account
|
|
209
|
+
* is created if the caller has none yet. The content, secrets included, passes through the
|
|
210
|
+
* platform. Requires `fleet:machines.login` on the machine.
|
|
211
|
+
*
|
|
212
|
+
* Fails with:
|
|
213
|
+
* - `MCP_CONFIGURATION_CHANGED` when the file is no longer at `expected_revision`;
|
|
214
|
+
* - `MCP_CONFIGURATION_INVALID` when `content` is not an object with an object `mcpServers`,
|
|
215
|
+
* with `metadata.line` and `metadata.column`;
|
|
216
|
+
* - `MACHINE_OFFLINE` when the machine is not connected and does not connect again in time;
|
|
217
|
+
* - `FEATURE_UNAVAILABLE` when the machine does not offer `leaflow.fleet.mcp.v1`;
|
|
218
|
+
* - `USER_NOT_FOUND`, `USER_NOT_ALLOWED`, `ACCOUNT_EXPIRED` or `PAM_PERMISSION_DENIED` when
|
|
219
|
+
* the machine refuses the account, as for opening a session;
|
|
220
|
+
* - `MACHINE_TIMEOUT` when the machine did not answer in time.
|
|
221
|
+
* @summary Replace the caller's MCP configuration on a machine
|
|
222
|
+
*/
|
|
223
|
+
export const replaceMcpConfiguration = async (machineId, replaceMcpConfigurationRequest, options, fetchFn) => {
|
|
224
|
+
const getHeaders = (h) => {
|
|
225
|
+
if (!h)
|
|
226
|
+
return {};
|
|
227
|
+
if (h instanceof Headers)
|
|
228
|
+
return Object.fromEntries(h.entries());
|
|
229
|
+
if (Symbol.iterator in h) {
|
|
230
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
231
|
+
}
|
|
232
|
+
const headers = {};
|
|
233
|
+
for (const [name, value] of Object.entries(h)) {
|
|
234
|
+
if (value !== undefined)
|
|
235
|
+
headers[name] = value;
|
|
236
|
+
}
|
|
237
|
+
return headers;
|
|
238
|
+
};
|
|
239
|
+
const res = await (fetchFn ?? fetch)(getReplaceMcpConfigurationUrl(machineId), {
|
|
240
|
+
...options,
|
|
241
|
+
method: "PUT",
|
|
242
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
243
|
+
body: JSON.stringify(replaceMcpConfigurationRequest),
|
|
244
|
+
});
|
|
245
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
246
|
+
const data = body ? JSON.parse(body) : {};
|
|
247
|
+
return { data, status: res.status, headers: res.headers };
|
|
248
|
+
};
|
|
249
|
+
export const getUpdateMcpServerUrl = (machineId, serverName) => {
|
|
250
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-servers/${encodeURIComponent(String(serverName))}`;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Adds a server to the caller's MCP configuration on the machine, or replaces the one with
|
|
254
|
+
* the same name. The values of `env` and `headers` the request gives, secrets included, pass
|
|
255
|
+
* through the platform; those named in `keep_env` and `keep_headers` stay as they are on the
|
|
256
|
+
* machine. The account is created if the caller has none yet. Requires
|
|
257
|
+
* `fleet:machines.login` on the machine.
|
|
258
|
+
*
|
|
259
|
+
* Fails with:
|
|
260
|
+
* - `MCP_CONFIGURATION_CHANGED` when the file is no longer at `expected_revision`;
|
|
261
|
+
* - `MCP_CONFIGURATION_INVALID` when the file cannot be read or is not valid; replace it
|
|
262
|
+
* whole first;
|
|
263
|
+
* - `MACHINE_OFFLINE` when the machine is not connected and does not connect again in time;
|
|
264
|
+
* - `FEATURE_UNAVAILABLE` when the machine does not offer `leaflow.fleet.mcp.v1`;
|
|
265
|
+
* - `USER_NOT_FOUND`, `USER_NOT_ALLOWED`, `ACCOUNT_EXPIRED` or `PAM_PERMISSION_DENIED` when
|
|
266
|
+
* the machine refuses the account, as for opening a session;
|
|
267
|
+
* - `MACHINE_TIMEOUT` when the machine did not answer in time.
|
|
268
|
+
* @summary Add or replace an MCP server
|
|
269
|
+
*/
|
|
270
|
+
export const updateMcpServer = async (machineId, serverName, updateMcpServerRequest, options, fetchFn) => {
|
|
271
|
+
const getHeaders = (h) => {
|
|
272
|
+
if (!h)
|
|
273
|
+
return {};
|
|
274
|
+
if (h instanceof Headers)
|
|
275
|
+
return Object.fromEntries(h.entries());
|
|
276
|
+
if (Symbol.iterator in h) {
|
|
277
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
278
|
+
}
|
|
279
|
+
const headers = {};
|
|
280
|
+
for (const [name, value] of Object.entries(h)) {
|
|
281
|
+
if (value !== undefined)
|
|
282
|
+
headers[name] = value;
|
|
283
|
+
}
|
|
284
|
+
return headers;
|
|
285
|
+
};
|
|
286
|
+
const res = await (fetchFn ?? fetch)(getUpdateMcpServerUrl(machineId, serverName), {
|
|
287
|
+
...options,
|
|
288
|
+
method: "PUT",
|
|
289
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
290
|
+
body: JSON.stringify(updateMcpServerRequest),
|
|
291
|
+
});
|
|
292
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
293
|
+
const data = body ? JSON.parse(body) : {};
|
|
294
|
+
return { data, status: res.status, headers: res.headers };
|
|
295
|
+
};
|
|
296
|
+
export const getDeleteMcpServerUrl = (machineId, serverName, params) => {
|
|
297
|
+
const normalizedParams = new URLSearchParams();
|
|
298
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
299
|
+
if (value !== undefined) {
|
|
300
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
const stringifiedParams = normalizedParams.toString();
|
|
304
|
+
return stringifiedParams.length > 0
|
|
305
|
+
? `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-servers/${encodeURIComponent(String(serverName))}?${stringifiedParams}`
|
|
306
|
+
: `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-servers/${encodeURIComponent(String(serverName))}`;
|
|
307
|
+
};
|
|
308
|
+
/**
|
|
309
|
+
* Removes a server from the caller's MCP configuration on the machine and stops it. Removing
|
|
310
|
+
* one that is not configured succeeds. Requires `fleet:machines.login` on the machine.
|
|
311
|
+
*
|
|
312
|
+
* Fails as replacing a server does.
|
|
313
|
+
* @summary Remove an MCP server
|
|
314
|
+
*/
|
|
315
|
+
export const deleteMcpServer = async (machineId, serverName, params, options, fetchFn) => {
|
|
316
|
+
const res = await (fetchFn ?? fetch)(getDeleteMcpServerUrl(machineId, serverName, params), {
|
|
317
|
+
...options,
|
|
318
|
+
method: "DELETE",
|
|
319
|
+
});
|
|
320
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
321
|
+
const data = body ? JSON.parse(body) : {};
|
|
322
|
+
return { data, status: res.status, headers: res.headers };
|
|
323
|
+
};
|
|
324
|
+
export const getSendMcpRequestUrl = (machineId, serverName) => {
|
|
325
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-servers/${encodeURIComponent(String(serverName))}:send`;
|
|
326
|
+
};
|
|
327
|
+
/**
|
|
328
|
+
* Sends one JSON-RPC request of MCP to one of the caller's servers on the machine, such as
|
|
329
|
+
* `tools/call`, `resources/read` or `prompts/get`, and returns the server's response. The
|
|
330
|
+
* machine starts or connects to the server if it is not running, and handles its
|
|
331
|
+
* initialization itself; a request still running when `timeout_seconds` passes is cancelled
|
|
332
|
+
* at the server. Requests the server makes of the client, such as for sampling, are refused,
|
|
333
|
+
* and its notifications, such as of progress, are dropped. A response with a JSON-RPC error
|
|
334
|
+
* is a successful request. Neither the request nor the response is hidden from the
|
|
335
|
+
* platform. Requires `fleet:machines.login` on the machine.
|
|
336
|
+
*
|
|
337
|
+
* Fails with:
|
|
338
|
+
* - `MCP_SERVER_NOT_FOUND` when the server is not configured;
|
|
339
|
+
* - `MCP_SERVER_UNAVAILABLE` when it could not be started or reached, with
|
|
340
|
+
* `metadata.failure`, an `McpServerFailure`;
|
|
341
|
+
* - `INVALID_ARGUMENT` when `request` is not one JSON-RPC request, such as a notification, or
|
|
342
|
+
* is one of initialization;
|
|
343
|
+
* - `RESULT_TOO_LARGE` when the response is larger than 8 MiB;
|
|
344
|
+
* - `MACHINE_OFFLINE` when the machine is not connected and does not connect again in time;
|
|
345
|
+
* - `FEATURE_UNAVAILABLE` when the machine does not offer `leaflow.fleet.mcp.v1`;
|
|
346
|
+
* - `USER_NOT_FOUND`, `USER_NOT_ALLOWED`, `ACCOUNT_EXPIRED` or `PAM_PERMISSION_DENIED` when
|
|
347
|
+
* the machine refuses the account, as for opening a session;
|
|
348
|
+
* - `MACHINE_TIMEOUT` when the machine did not answer in time.
|
|
349
|
+
* @summary Send an MCP request to a server
|
|
350
|
+
*/
|
|
351
|
+
export const sendMcpRequest = async (machineId, serverName, sendMcpRequestRequest, options, fetchFn) => {
|
|
352
|
+
const getHeaders = (h) => {
|
|
353
|
+
if (!h)
|
|
354
|
+
return {};
|
|
355
|
+
if (h instanceof Headers)
|
|
356
|
+
return Object.fromEntries(h.entries());
|
|
357
|
+
if (Symbol.iterator in h) {
|
|
358
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
359
|
+
}
|
|
360
|
+
const headers = {};
|
|
361
|
+
for (const [name, value] of Object.entries(h)) {
|
|
362
|
+
if (value !== undefined)
|
|
363
|
+
headers[name] = value;
|
|
364
|
+
}
|
|
365
|
+
return headers;
|
|
366
|
+
};
|
|
367
|
+
const res = await (fetchFn ?? fetch)(getSendMcpRequestUrl(machineId, serverName), {
|
|
368
|
+
...options,
|
|
369
|
+
method: "POST",
|
|
370
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
371
|
+
body: JSON.stringify(sendMcpRequestRequest),
|
|
372
|
+
});
|
|
373
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
374
|
+
const data = body ? JSON.parse(body) : {};
|
|
375
|
+
return { data, status: res.status, headers: res.headers };
|
|
376
|
+
};
|
|
377
|
+
export const getCallMcpToolUrl = (machineId, serverName, toolName) => {
|
|
378
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-servers/${encodeURIComponent(String(serverName))}/tools/${encodeURIComponent(String(toolName))}:call`;
|
|
379
|
+
};
|
|
380
|
+
/**
|
|
381
|
+
* Calls one tool of one of the caller's servers on the machine and returns its MCP
|
|
382
|
+
* `CallToolResult`. A tool that reports an error, with `isError`, is a successful request. A
|
|
383
|
+
* tool whose name cannot appear in a path is called with `send-mcp-request`. Neither the
|
|
384
|
+
* arguments nor the result is hidden from the platform. Requires `fleet:machines.login` on
|
|
385
|
+
* the machine.
|
|
386
|
+
*
|
|
387
|
+
* Fails as sending a request does, and with `MCP_REQUEST_FAILED` when the server answers
|
|
388
|
+
* with a JSON-RPC error, such as for a tool it does not offer or arguments it does not
|
|
389
|
+
* accept, with the error's `metadata.code` and `metadata.message`.
|
|
390
|
+
* @summary Call an MCP tool
|
|
391
|
+
*/
|
|
392
|
+
export const callMcpTool = async (machineId, serverName, toolName, callMcpToolRequest, options, fetchFn) => {
|
|
393
|
+
const getHeaders = (h) => {
|
|
394
|
+
if (!h)
|
|
395
|
+
return {};
|
|
396
|
+
if (h instanceof Headers)
|
|
397
|
+
return Object.fromEntries(h.entries());
|
|
398
|
+
if (Symbol.iterator in h) {
|
|
399
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
400
|
+
}
|
|
401
|
+
const headers = {};
|
|
402
|
+
for (const [name, value] of Object.entries(h)) {
|
|
403
|
+
if (value !== undefined)
|
|
404
|
+
headers[name] = value;
|
|
405
|
+
}
|
|
406
|
+
return headers;
|
|
407
|
+
};
|
|
408
|
+
const res = await (fetchFn ?? fetch)(getCallMcpToolUrl(machineId, serverName, toolName), {
|
|
409
|
+
...options,
|
|
410
|
+
method: "POST",
|
|
411
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
412
|
+
body: JSON.stringify(callMcpToolRequest),
|
|
413
|
+
});
|
|
414
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
415
|
+
const data = body ? JSON.parse(body) : {};
|
|
416
|
+
return { data, status: res.status, headers: res.headers };
|
|
417
|
+
};
|
|
418
|
+
export const getListMcpToolsUrl = (machineId, params) => {
|
|
419
|
+
const normalizedParams = new URLSearchParams();
|
|
420
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
421
|
+
if (value !== undefined) {
|
|
422
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
const stringifiedParams = normalizedParams.toString();
|
|
426
|
+
return stringifiedParams.length > 0
|
|
427
|
+
? `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-tools?${stringifiedParams}`
|
|
428
|
+
: `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/mcp-tools`;
|
|
429
|
+
};
|
|
430
|
+
/**
|
|
431
|
+
* Lists the tools of the caller's servers on the machine, or of one of them, that match
|
|
432
|
+
* `query`: every word of it, ignoring case, in the tool's name, title or description. They
|
|
433
|
+
* are ordered by server, then by tool name. Servers that are not running are started to
|
|
434
|
+
* learn their tools; one that cannot be is named in `unavailable_servers`, and the others are
|
|
435
|
+
* listed anyway. Slow servers do not hold the request up: those still starting are named
|
|
436
|
+
* with `timeout` and go on starting, so that a later request lists their tools. Requires
|
|
437
|
+
* `fleet:machines.login` on the machine.
|
|
438
|
+
*
|
|
439
|
+
* Fails with:
|
|
440
|
+
* - `MCP_SERVER_NOT_FOUND` when `server` is not configured;
|
|
441
|
+
* - `MACHINE_OFFLINE` when the machine is not connected and does not connect again in time;
|
|
442
|
+
* - `FEATURE_UNAVAILABLE` when the machine does not offer `leaflow.fleet.mcp.v1`;
|
|
443
|
+
* - `USER_NOT_FOUND`, `USER_NOT_ALLOWED`, `ACCOUNT_EXPIRED` or `PAM_PERMISSION_DENIED` when
|
|
444
|
+
* the machine refuses the account, as for opening a session;
|
|
445
|
+
* - `MACHINE_TIMEOUT` when the machine did not answer in time.
|
|
446
|
+
* @summary List the caller's MCP tools on a machine
|
|
447
|
+
*/
|
|
448
|
+
export const listMcpTools = async (machineId, params, options, fetchFn) => {
|
|
449
|
+
const res = await (fetchFn ?? fetch)(getListMcpToolsUrl(machineId, params), {
|
|
450
|
+
...options,
|
|
451
|
+
method: "GET",
|
|
452
|
+
});
|
|
453
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
454
|
+
const data = body ? JSON.parse(body) : {};
|
|
455
|
+
return { data, status: res.status, headers: res.headers };
|
|
456
|
+
};
|
|
457
|
+
export const getGetPrivilegeAutoApprovalUrl = (machineId) => {
|
|
458
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/privilege-auto-approval`;
|
|
459
|
+
};
|
|
460
|
+
/**
|
|
461
|
+
* Returns the caller's automatic approval of their privilege requests on the machine. Fails
|
|
462
|
+
* with `PRIVILEGE_AUTO_APPROVAL_NOT_FOUND` while the caller is asked every time, including
|
|
463
|
+
* after its `expires_at` has passed.
|
|
464
|
+
* @summary Get the caller's automatic approval for a machine
|
|
465
|
+
*/
|
|
466
|
+
export const getPrivilegeAutoApproval = async (machineId, options, fetchFn) => {
|
|
467
|
+
const res = await (fetchFn ?? fetch)(getGetPrivilegeAutoApprovalUrl(machineId), {
|
|
468
|
+
...options,
|
|
469
|
+
method: "GET",
|
|
470
|
+
});
|
|
471
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
472
|
+
const data = body ? JSON.parse(body) : {};
|
|
473
|
+
return { data, status: res.status, headers: res.headers };
|
|
474
|
+
};
|
|
475
|
+
export const getUpdatePrivilegeAutoApprovalUrl = (machineId) => {
|
|
476
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/privilege-auto-approval`;
|
|
477
|
+
};
|
|
478
|
+
/**
|
|
479
|
+
* Approves the caller's privilege requests on the machine at once, until `expires_at`, or
|
|
480
|
+
* until removed when `expires_at` is null, replacing any earlier automatic approval. It
|
|
481
|
+
* applies to the caller's own account only, which is created if the caller has none yet,
|
|
482
|
+
* and only while they may become root on the machine. Fails with `INVALID_ARGUMENT` when
|
|
483
|
+
* `expires_at` has passed.
|
|
484
|
+
* @summary Approve the caller's privilege requests on a machine without asking
|
|
485
|
+
*/
|
|
486
|
+
export const updatePrivilegeAutoApproval = async (machineId, updatePrivilegeAutoApprovalRequest, options, fetchFn) => {
|
|
487
|
+
const getHeaders = (h) => {
|
|
488
|
+
if (!h)
|
|
489
|
+
return {};
|
|
490
|
+
if (h instanceof Headers)
|
|
491
|
+
return Object.fromEntries(h.entries());
|
|
492
|
+
if (Symbol.iterator in h) {
|
|
493
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
494
|
+
}
|
|
495
|
+
const headers = {};
|
|
496
|
+
for (const [name, value] of Object.entries(h)) {
|
|
497
|
+
if (value !== undefined)
|
|
498
|
+
headers[name] = value;
|
|
499
|
+
}
|
|
500
|
+
return headers;
|
|
501
|
+
};
|
|
502
|
+
const res = await (fetchFn ?? fetch)(getUpdatePrivilegeAutoApprovalUrl(machineId), {
|
|
503
|
+
...options,
|
|
504
|
+
method: "PUT",
|
|
505
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
506
|
+
body: JSON.stringify(updatePrivilegeAutoApprovalRequest),
|
|
507
|
+
});
|
|
508
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
509
|
+
const data = body ? JSON.parse(body) : {};
|
|
510
|
+
return { data, status: res.status, headers: res.headers };
|
|
511
|
+
};
|
|
512
|
+
export const getDeletePrivilegeAutoApprovalUrl = (machineId) => {
|
|
513
|
+
return `https://fleet.leaflow.cloud/api/v1/machines/${encodeURIComponent(String(machineId))}/privilege-auto-approval`;
|
|
514
|
+
};
|
|
515
|
+
/**
|
|
516
|
+
* Removes it: the caller is asked about every later privilege request on the machine.
|
|
517
|
+
* Removing one that does not exist succeeds.
|
|
518
|
+
* @summary Remove the caller's automatic approval for a machine
|
|
519
|
+
*/
|
|
520
|
+
export const deletePrivilegeAutoApproval = async (machineId, options, fetchFn) => {
|
|
521
|
+
const res = await (fetchFn ?? fetch)(getDeletePrivilegeAutoApprovalUrl(machineId), {
|
|
522
|
+
...options,
|
|
523
|
+
method: "DELETE",
|
|
524
|
+
});
|
|
525
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
526
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
527
|
+
return { data, status: res.status, headers: res.headers };
|
|
528
|
+
};
|
|
529
|
+
export const getListPrivilegeAutoApprovalsUrl = (params) => {
|
|
530
|
+
const normalizedParams = new URLSearchParams();
|
|
531
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
532
|
+
if (value !== undefined) {
|
|
533
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
const stringifiedParams = normalizedParams.toString();
|
|
537
|
+
return stringifiedParams.length > 0
|
|
538
|
+
? `https://fleet.leaflow.cloud/api/v1/privilege-auto-approvals?${stringifiedParams}`
|
|
539
|
+
: `https://fleet.leaflow.cloud/api/v1/privilege-auto-approvals`;
|
|
540
|
+
};
|
|
541
|
+
/**
|
|
542
|
+
* Returns the caller's automatic approvals on the machines of the current project that are
|
|
543
|
+
* in effect, the most recently set first.
|
|
544
|
+
* @summary List the caller's automatic approvals
|
|
545
|
+
*/
|
|
546
|
+
export const listPrivilegeAutoApprovals = async (params, options, fetchFn) => {
|
|
547
|
+
const res = await (fetchFn ?? fetch)(getListPrivilegeAutoApprovalsUrl(params), {
|
|
548
|
+
...options,
|
|
549
|
+
method: "GET",
|
|
550
|
+
});
|
|
551
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
552
|
+
const data = body ? JSON.parse(body) : {};
|
|
553
|
+
return { data, status: res.status, headers: res.headers };
|
|
554
|
+
};
|
|
555
|
+
export const getListPrivilegeRequestsUrl = (params) => {
|
|
556
|
+
const normalizedParams = new URLSearchParams();
|
|
557
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
558
|
+
if (value !== undefined) {
|
|
559
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
const stringifiedParams = normalizedParams.toString();
|
|
563
|
+
return stringifiedParams.length > 0
|
|
564
|
+
? `https://fleet.leaflow.cloud/api/v1/privilege-requests?${stringifiedParams}`
|
|
565
|
+
: `https://fleet.leaflow.cloud/api/v1/privilege-requests`;
|
|
566
|
+
};
|
|
567
|
+
/**
|
|
568
|
+
* Returns the caller's privilege requests on the project's machines, newest first. Requests
|
|
569
|
+
* are kept for 30 days.
|
|
570
|
+
* @summary List the caller's privilege requests
|
|
571
|
+
*/
|
|
572
|
+
export const listPrivilegeRequests = async (params, options, fetchFn) => {
|
|
573
|
+
const res = await (fetchFn ?? fetch)(getListPrivilegeRequestsUrl(params), {
|
|
574
|
+
...options,
|
|
575
|
+
method: "GET",
|
|
576
|
+
});
|
|
577
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
578
|
+
const data = body ? JSON.parse(body) : {};
|
|
579
|
+
return { data, status: res.status, headers: res.headers };
|
|
580
|
+
};
|
|
581
|
+
export const getGetPrivilegeRequestUrl = (requestId) => {
|
|
582
|
+
return `https://fleet.leaflow.cloud/api/v1/privilege-requests/${encodeURIComponent(String(requestId))}`;
|
|
583
|
+
};
|
|
584
|
+
/**
|
|
585
|
+
* Returns one of the caller's privilege requests.
|
|
586
|
+
* @summary Get a privilege request
|
|
587
|
+
*/
|
|
588
|
+
export const getPrivilegeRequest = async (requestId, options, fetchFn) => {
|
|
589
|
+
const res = await (fetchFn ?? fetch)(getGetPrivilegeRequestUrl(requestId), {
|
|
590
|
+
...options,
|
|
591
|
+
method: "GET",
|
|
592
|
+
});
|
|
593
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
594
|
+
const data = body ? JSON.parse(body) : {};
|
|
595
|
+
return { data, status: res.status, headers: res.headers };
|
|
596
|
+
};
|
|
597
|
+
export const getApprovePrivilegeRequestUrl = (requestId) => {
|
|
598
|
+
return `https://fleet.leaflow.cloud/api/v1/privilege-requests/${encodeURIComponent(String(requestId))}:approve`;
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* Approves one of the caller's pending requests; the waiting sudo goes on as root. Fails with
|
|
602
|
+
* `PRIVILEGE_REQUEST_CLOSED` when the request is no longer pending, with `metadata.state`
|
|
603
|
+
* giving how it ended.
|
|
604
|
+
* @summary Approve a privilege request
|
|
605
|
+
*/
|
|
606
|
+
export const approvePrivilegeRequest = async (requestId, options, fetchFn) => {
|
|
607
|
+
const res = await (fetchFn ?? fetch)(getApprovePrivilegeRequestUrl(requestId), {
|
|
608
|
+
...options,
|
|
609
|
+
method: "POST",
|
|
610
|
+
});
|
|
611
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
612
|
+
const data = body ? JSON.parse(body) : {};
|
|
613
|
+
return { data, status: res.status, headers: res.headers };
|
|
614
|
+
};
|
|
615
|
+
export const getDenyPrivilegeRequestUrl = (requestId) => {
|
|
616
|
+
return `https://fleet.leaflow.cloud/api/v1/privilege-requests/${encodeURIComponent(String(requestId))}:deny`;
|
|
617
|
+
};
|
|
618
|
+
/**
|
|
619
|
+
* Denies one of the caller's pending requests; the waiting sudo fails. Fails with
|
|
620
|
+
* `PRIVILEGE_REQUEST_CLOSED` as for approving.
|
|
621
|
+
* @summary Deny a privilege request
|
|
622
|
+
*/
|
|
623
|
+
export const denyPrivilegeRequest = async (requestId, options, fetchFn) => {
|
|
624
|
+
const res = await (fetchFn ?? fetch)(getDenyPrivilegeRequestUrl(requestId), {
|
|
625
|
+
...options,
|
|
626
|
+
method: "POST",
|
|
627
|
+
});
|
|
628
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
629
|
+
const data = body ? JSON.parse(body) : {};
|
|
630
|
+
return { data, status: res.status, headers: res.headers };
|
|
631
|
+
};
|
|
632
|
+
export const getFindEnrollmentByPairingCodeUrl = (params) => {
|
|
633
|
+
const normalizedParams = new URLSearchParams();
|
|
634
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
635
|
+
if (value !== undefined) {
|
|
636
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
const stringifiedParams = normalizedParams.toString();
|
|
640
|
+
return stringifiedParams.length > 0
|
|
641
|
+
? `https://fleet.leaflow.cloud/api/v1/enrollments:find?${stringifiedParams}`
|
|
642
|
+
: `https://fleet.leaflow.cloud/api/v1/enrollments:find`;
|
|
643
|
+
};
|
|
644
|
+
/**
|
|
645
|
+
* Returns the pending enrollment request whose pairing code matches, or no enrollment when
|
|
646
|
+
* none does. Mistyped codes are expected and are not an error. Letters are matched
|
|
647
|
+
* case-insensitively, `I` and `L` are read as `1`, `O` as `0`, and spaces and hyphens are
|
|
648
|
+
* ignored.
|
|
649
|
+
*
|
|
650
|
+
* Only requests that are still pending are found. A request is pending while its machine
|
|
651
|
+
* keeps polling; one it stops polling expires after a few hours.
|
|
652
|
+
*
|
|
653
|
+
* Requires `fleet:machines.manage`.
|
|
654
|
+
* @summary Find an enrollment request by its pairing code
|
|
655
|
+
*/
|
|
656
|
+
export const findEnrollmentByPairingCode = async (params, options, fetchFn) => {
|
|
657
|
+
const res = await (fetchFn ?? fetch)(getFindEnrollmentByPairingCodeUrl(params), {
|
|
658
|
+
...options,
|
|
659
|
+
method: "GET",
|
|
660
|
+
});
|
|
661
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
662
|
+
const data = body ? JSON.parse(body) : {};
|
|
663
|
+
return { data, status: res.status, headers: res.headers };
|
|
664
|
+
};
|
|
665
|
+
export const getApproveEnrollmentUrl = (enrollmentId) => {
|
|
666
|
+
return `https://fleet.leaflow.cloud/api/v1/enrollments/${encodeURIComponent(String(enrollmentId))}:approve`;
|
|
667
|
+
};
|
|
668
|
+
/**
|
|
669
|
+
* Adds the machine to the current project under the given name and returns it. The Agent
|
|
670
|
+
* learns the decision the next time it polls.
|
|
671
|
+
*
|
|
672
|
+
* A request that is no longer pending is rejected with `ENROLLMENT_NOT_PENDING`.
|
|
673
|
+
*
|
|
674
|
+
* Requires `fleet:machines.manage`.
|
|
675
|
+
* @summary Approve an enrollment request
|
|
676
|
+
*/
|
|
677
|
+
export const approveEnrollment = async (enrollmentId, approveEnrollmentRequest, options, fetchFn) => {
|
|
678
|
+
const getHeaders = (h) => {
|
|
679
|
+
if (!h)
|
|
680
|
+
return {};
|
|
681
|
+
if (h instanceof Headers)
|
|
682
|
+
return Object.fromEntries(h.entries());
|
|
683
|
+
if (Symbol.iterator in h) {
|
|
684
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
685
|
+
}
|
|
686
|
+
const headers = {};
|
|
687
|
+
for (const [name, value] of Object.entries(h)) {
|
|
688
|
+
if (value !== undefined)
|
|
689
|
+
headers[name] = value;
|
|
690
|
+
}
|
|
691
|
+
return headers;
|
|
692
|
+
};
|
|
693
|
+
const res = await (fetchFn ?? fetch)(getApproveEnrollmentUrl(enrollmentId), {
|
|
694
|
+
...options,
|
|
695
|
+
method: "POST",
|
|
696
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
697
|
+
body: JSON.stringify(approveEnrollmentRequest),
|
|
698
|
+
});
|
|
699
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
700
|
+
const data = body ? JSON.parse(body) : {};
|
|
701
|
+
return { data, status: res.status, headers: res.headers };
|
|
702
|
+
};
|
|
703
|
+
export const getDenyEnrollmentUrl = (enrollmentId) => {
|
|
704
|
+
return `https://fleet.leaflow.cloud/api/v1/enrollments/${encodeURIComponent(String(enrollmentId))}:deny`;
|
|
705
|
+
};
|
|
706
|
+
/**
|
|
707
|
+
* Refuses the request. The decision is final for the machine's key: the Agent stops
|
|
708
|
+
* polling and reports that it was denied.
|
|
709
|
+
*
|
|
710
|
+
* A request that is no longer pending is rejected with `ENROLLMENT_NOT_PENDING`.
|
|
711
|
+
*
|
|
712
|
+
* Requires `fleet:machines.manage`.
|
|
713
|
+
* @summary Deny an enrollment request
|
|
714
|
+
*/
|
|
715
|
+
export const denyEnrollment = async (enrollmentId, options, fetchFn) => {
|
|
716
|
+
const res = await (fetchFn ?? fetch)(getDenyEnrollmentUrl(enrollmentId), {
|
|
717
|
+
...options,
|
|
718
|
+
method: "POST",
|
|
719
|
+
});
|
|
720
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
721
|
+
const data = body ? JSON.parse(body) : {};
|
|
722
|
+
return { data, status: res.status, headers: res.headers };
|
|
723
|
+
};
|
|
724
|
+
export const getListMachineRegistrationsUrl = (params) => {
|
|
725
|
+
const normalizedParams = new URLSearchParams();
|
|
726
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
727
|
+
if (value !== undefined) {
|
|
728
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
const stringifiedParams = normalizedParams.toString();
|
|
732
|
+
return stringifiedParams.length > 0
|
|
733
|
+
? `https://fleet.leaflow.cloud/api/v1/machine-registrations?${stringifiedParams}`
|
|
734
|
+
: `https://fleet.leaflow.cloud/api/v1/machine-registrations`;
|
|
735
|
+
};
|
|
736
|
+
/**
|
|
737
|
+
* Returns the registrations of the current project, newest first. Registrations are kept
|
|
738
|
+
* for 30 days.
|
|
739
|
+
*
|
|
740
|
+
* Requires `fleet:machines.manage`.
|
|
741
|
+
* @summary List machine registrations
|
|
742
|
+
*/
|
|
743
|
+
export const listMachineRegistrations = async (params, options, fetchFn) => {
|
|
744
|
+
const res = await (fetchFn ?? fetch)(getListMachineRegistrationsUrl(params), {
|
|
745
|
+
...options,
|
|
746
|
+
method: "GET",
|
|
747
|
+
});
|
|
748
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
749
|
+
const data = body ? JSON.parse(body) : {};
|
|
750
|
+
return { data, status: res.status, headers: res.headers };
|
|
751
|
+
};
|
|
752
|
+
export const getCreateMachineRegistrationUrl = () => {
|
|
753
|
+
return `https://fleet.leaflow.cloud/api/v1/machine-registrations`;
|
|
754
|
+
};
|
|
755
|
+
/**
|
|
756
|
+
* Reserves a machine in the current project under the given name and returns the
|
|
757
|
+
* registration with a one-time token. A machine that presents the token when it enrolls
|
|
758
|
+
* joins the project as `registration.machine_id` without approval. The token is returned
|
|
759
|
+
* only in this response and cannot be read again.
|
|
760
|
+
*
|
|
761
|
+
* Requires `fleet:machines.manage`.
|
|
762
|
+
* @summary Create a machine registration
|
|
763
|
+
*/
|
|
764
|
+
export const createMachineRegistration = async (createMachineRegistrationRequest, options, fetchFn) => {
|
|
765
|
+
const getHeaders = (h) => {
|
|
766
|
+
if (!h)
|
|
767
|
+
return {};
|
|
768
|
+
if (h instanceof Headers)
|
|
769
|
+
return Object.fromEntries(h.entries());
|
|
770
|
+
if (Symbol.iterator in h) {
|
|
771
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
772
|
+
}
|
|
773
|
+
const headers = {};
|
|
774
|
+
for (const [name, value] of Object.entries(h)) {
|
|
775
|
+
if (value !== undefined)
|
|
776
|
+
headers[name] = value;
|
|
777
|
+
}
|
|
778
|
+
return headers;
|
|
779
|
+
};
|
|
780
|
+
const res = await (fetchFn ?? fetch)(getCreateMachineRegistrationUrl(), {
|
|
781
|
+
...options,
|
|
782
|
+
method: "POST",
|
|
783
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
784
|
+
body: JSON.stringify(createMachineRegistrationRequest),
|
|
785
|
+
});
|
|
786
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
787
|
+
const data = body ? JSON.parse(body) : {};
|
|
788
|
+
return { data, status: res.status, headers: res.headers };
|
|
789
|
+
};
|
|
790
|
+
export const getGetMachineRegistrationUrl = (registrationId) => {
|
|
791
|
+
return `https://fleet.leaflow.cloud/api/v1/machine-registrations/${encodeURIComponent(String(registrationId))}`;
|
|
792
|
+
};
|
|
793
|
+
/**
|
|
794
|
+
* Requires `fleet:machines.manage`.
|
|
795
|
+
* @summary Get a machine registration
|
|
796
|
+
*/
|
|
797
|
+
export const getMachineRegistration = async (registrationId, options, fetchFn) => {
|
|
798
|
+
const res = await (fetchFn ?? fetch)(getGetMachineRegistrationUrl(registrationId), {
|
|
799
|
+
...options,
|
|
800
|
+
method: "GET",
|
|
801
|
+
});
|
|
802
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
803
|
+
const data = body ? JSON.parse(body) : {};
|
|
804
|
+
return { data, status: res.status, headers: res.headers };
|
|
805
|
+
};
|
|
806
|
+
export const getDeleteMachineRegistrationUrl = (registrationId) => {
|
|
807
|
+
return `https://fleet.leaflow.cloud/api/v1/machine-registrations/${encodeURIComponent(String(registrationId))}`;
|
|
808
|
+
};
|
|
809
|
+
/**
|
|
810
|
+
* Revokes the registration: its token no longer enrolls a machine. Revoking a registration
|
|
811
|
+
* that is already revoked or expired succeeds and changes nothing else. A registration that
|
|
812
|
+
* a machine has used is rejected with `MACHINE_REGISTRATION_USED`; to remove that machine,
|
|
813
|
+
* delete the machine.
|
|
814
|
+
*
|
|
815
|
+
* Requires `fleet:machines.manage`.
|
|
816
|
+
* @summary Revoke a machine registration
|
|
817
|
+
*/
|
|
818
|
+
export const deleteMachineRegistration = async (registrationId, options, fetchFn) => {
|
|
819
|
+
const res = await (fetchFn ?? fetch)(getDeleteMachineRegistrationUrl(registrationId), {
|
|
820
|
+
...options,
|
|
821
|
+
method: "DELETE",
|
|
822
|
+
});
|
|
823
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
824
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
825
|
+
return { data, status: res.status, headers: res.headers };
|
|
826
|
+
};
|
|
827
|
+
export const getListAccountsUrl = (params) => {
|
|
828
|
+
const normalizedParams = new URLSearchParams();
|
|
829
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
830
|
+
if (value !== undefined) {
|
|
831
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
const stringifiedParams = normalizedParams.toString();
|
|
835
|
+
return stringifiedParams.length > 0
|
|
836
|
+
? `https://fleet.leaflow.cloud/api/v1/accounts?${stringifiedParams}`
|
|
837
|
+
: `https://fleet.leaflow.cloud/api/v1/accounts`;
|
|
838
|
+
};
|
|
839
|
+
/**
|
|
840
|
+
* Returns the accounts of the project's members, ordered by username. A member who has never
|
|
841
|
+
* been able to log in to a machine has no account yet.
|
|
842
|
+
* @summary List accounts
|
|
843
|
+
*/
|
|
844
|
+
export const listAccounts = async (params, options, fetchFn) => {
|
|
845
|
+
const res = await (fetchFn ?? fetch)(getListAccountsUrl(params), {
|
|
846
|
+
...options,
|
|
847
|
+
method: "GET",
|
|
848
|
+
});
|
|
849
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
850
|
+
const data = body ? JSON.parse(body) : {};
|
|
851
|
+
return { data, status: res.status, headers: res.headers };
|
|
852
|
+
};
|
|
853
|
+
export const getGetAccountUrl = (accountId) => {
|
|
854
|
+
return `https://fleet.leaflow.cloud/api/v1/accounts/${encodeURIComponent(String(accountId))}`;
|
|
855
|
+
};
|
|
856
|
+
/**
|
|
857
|
+
* Returns the account of a member of the project.
|
|
858
|
+
* @summary Get an account
|
|
859
|
+
*/
|
|
860
|
+
export const getAccount = async (accountId, options, fetchFn) => {
|
|
861
|
+
const res = await (fetchFn ?? fetch)(getGetAccountUrl(accountId), {
|
|
862
|
+
...options,
|
|
863
|
+
method: "GET",
|
|
864
|
+
});
|
|
865
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
866
|
+
const data = body ? JSON.parse(body) : {};
|
|
867
|
+
return { data, status: res.status, headers: res.headers };
|
|
868
|
+
};
|
|
869
|
+
export const getUpdateAccountUrl = (accountId) => {
|
|
870
|
+
return `https://fleet.leaflow.cloud/api/v1/accounts/${encodeURIComponent(String(accountId))}`;
|
|
871
|
+
};
|
|
872
|
+
/**
|
|
873
|
+
* Changes the caller's own account, only the fields present in the request. The account is
|
|
874
|
+
* the same in every project, and a new username takes effect on the machines of all of them
|
|
875
|
+
* within about a minute; the uid stays, so files keep their owner.
|
|
876
|
+
*
|
|
877
|
+
* Fails with:
|
|
878
|
+
* - `ACCOUNT_NOT_OWNED` when the account is another member's;
|
|
879
|
+
* - `DIRECTORY_NAME_TAKEN` when another account or a group uses the username.
|
|
880
|
+
* @summary Update an account
|
|
881
|
+
*/
|
|
882
|
+
export const updateAccount = async (accountId, updateAccountRequest, options, fetchFn) => {
|
|
883
|
+
const getHeaders = (h) => {
|
|
884
|
+
if (!h)
|
|
885
|
+
return {};
|
|
886
|
+
if (h instanceof Headers)
|
|
887
|
+
return Object.fromEntries(h.entries());
|
|
888
|
+
if (Symbol.iterator in h) {
|
|
889
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
890
|
+
}
|
|
891
|
+
const headers = {};
|
|
892
|
+
for (const [name, value] of Object.entries(h)) {
|
|
893
|
+
if (value !== undefined)
|
|
894
|
+
headers[name] = value;
|
|
895
|
+
}
|
|
896
|
+
return headers;
|
|
897
|
+
};
|
|
898
|
+
const res = await (fetchFn ?? fetch)(getUpdateAccountUrl(accountId), {
|
|
899
|
+
...options,
|
|
900
|
+
method: "PATCH",
|
|
901
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
902
|
+
body: JSON.stringify(updateAccountRequest),
|
|
903
|
+
});
|
|
904
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
905
|
+
const data = body ? JSON.parse(body) : {};
|
|
906
|
+
return { data, status: res.status, headers: res.headers };
|
|
907
|
+
};
|
|
908
|
+
export const getListGroupsUrl = (params) => {
|
|
909
|
+
const normalizedParams = new URLSearchParams();
|
|
910
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
911
|
+
if (value !== undefined) {
|
|
912
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
const stringifiedParams = normalizedParams.toString();
|
|
916
|
+
return stringifiedParams.length > 0
|
|
917
|
+
? `https://fleet.leaflow.cloud/api/v1/groups?${stringifiedParams}`
|
|
918
|
+
: `https://fleet.leaflow.cloud/api/v1/groups`;
|
|
919
|
+
};
|
|
920
|
+
/**
|
|
921
|
+
* Returns the groups of the project's directory, ordered by name.
|
|
922
|
+
* @summary List groups
|
|
923
|
+
*/
|
|
924
|
+
export const listGroups = async (params, options, fetchFn) => {
|
|
925
|
+
const res = await (fetchFn ?? fetch)(getListGroupsUrl(params), {
|
|
926
|
+
...options,
|
|
927
|
+
method: "GET",
|
|
928
|
+
});
|
|
929
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
930
|
+
const data = body ? JSON.parse(body) : {};
|
|
931
|
+
return { data, status: res.status, headers: res.headers };
|
|
932
|
+
};
|
|
933
|
+
export const getCreateGroupUrl = () => {
|
|
934
|
+
return `https://fleet.leaflow.cloud/api/v1/groups`;
|
|
935
|
+
};
|
|
936
|
+
/**
|
|
937
|
+
* Creates a group in the project's directory. It reaches the machines within about a minute.
|
|
938
|
+
*
|
|
939
|
+
* Fails with `DIRECTORY_NAME_TAKEN` when an account, or another group of the project, uses the
|
|
940
|
+
* name.
|
|
941
|
+
*
|
|
942
|
+
* Requires `fleet:directory.manage`.
|
|
943
|
+
* @summary Create a group
|
|
944
|
+
*/
|
|
945
|
+
export const createGroup = async (createGroupRequest, options, fetchFn) => {
|
|
946
|
+
const getHeaders = (h) => {
|
|
947
|
+
if (!h)
|
|
948
|
+
return {};
|
|
949
|
+
if (h instanceof Headers)
|
|
950
|
+
return Object.fromEntries(h.entries());
|
|
951
|
+
if (Symbol.iterator in h) {
|
|
952
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
953
|
+
}
|
|
954
|
+
const headers = {};
|
|
955
|
+
for (const [name, value] of Object.entries(h)) {
|
|
956
|
+
if (value !== undefined)
|
|
957
|
+
headers[name] = value;
|
|
958
|
+
}
|
|
959
|
+
return headers;
|
|
960
|
+
};
|
|
961
|
+
const res = await (fetchFn ?? fetch)(getCreateGroupUrl(), {
|
|
962
|
+
...options,
|
|
963
|
+
method: "POST",
|
|
964
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
965
|
+
body: JSON.stringify(createGroupRequest),
|
|
966
|
+
});
|
|
967
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
968
|
+
const data = body ? JSON.parse(body) : {};
|
|
969
|
+
return { data, status: res.status, headers: res.headers };
|
|
970
|
+
};
|
|
971
|
+
export const getGetGroupUrl = (groupId) => {
|
|
972
|
+
return `https://fleet.leaflow.cloud/api/v1/groups/${encodeURIComponent(String(groupId))}`;
|
|
973
|
+
};
|
|
974
|
+
/**
|
|
975
|
+
* @summary Get a group
|
|
976
|
+
*/
|
|
977
|
+
export const getGroup = async (groupId, options, fetchFn) => {
|
|
978
|
+
const res = await (fetchFn ?? fetch)(getGetGroupUrl(groupId), {
|
|
979
|
+
...options,
|
|
980
|
+
method: "GET",
|
|
981
|
+
});
|
|
982
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
983
|
+
const data = body ? JSON.parse(body) : {};
|
|
984
|
+
return { data, status: res.status, headers: res.headers };
|
|
985
|
+
};
|
|
986
|
+
export const getUpdateGroupUrl = (groupId) => {
|
|
987
|
+
return `https://fleet.leaflow.cloud/api/v1/groups/${encodeURIComponent(String(groupId))}`;
|
|
988
|
+
};
|
|
989
|
+
/**
|
|
990
|
+
* The gid stays, so files keep their group. Fails with `DIRECTORY_NAME_TAKEN` as for creating
|
|
991
|
+
* a group.
|
|
992
|
+
*
|
|
993
|
+
* Requires `fleet:directory.manage`.
|
|
994
|
+
* @summary Rename a group
|
|
995
|
+
*/
|
|
996
|
+
export const updateGroup = async (groupId, updateGroupRequest, options, fetchFn) => {
|
|
997
|
+
const getHeaders = (h) => {
|
|
998
|
+
if (!h)
|
|
999
|
+
return {};
|
|
1000
|
+
if (h instanceof Headers)
|
|
1001
|
+
return Object.fromEntries(h.entries());
|
|
1002
|
+
if (Symbol.iterator in h) {
|
|
1003
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1004
|
+
}
|
|
1005
|
+
const headers = {};
|
|
1006
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1007
|
+
if (value !== undefined)
|
|
1008
|
+
headers[name] = value;
|
|
1009
|
+
}
|
|
1010
|
+
return headers;
|
|
1011
|
+
};
|
|
1012
|
+
const res = await (fetchFn ?? fetch)(getUpdateGroupUrl(groupId), {
|
|
1013
|
+
...options,
|
|
1014
|
+
method: "PATCH",
|
|
1015
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1016
|
+
body: JSON.stringify(updateGroupRequest),
|
|
1017
|
+
});
|
|
1018
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1019
|
+
const data = body ? JSON.parse(body) : {};
|
|
1020
|
+
return { data, status: res.status, headers: res.headers };
|
|
1021
|
+
};
|
|
1022
|
+
export const getDeleteGroupUrl = (groupId) => {
|
|
1023
|
+
return `https://fleet.leaflow.cloud/api/v1/groups/${encodeURIComponent(String(groupId))}`;
|
|
1024
|
+
};
|
|
1025
|
+
/**
|
|
1026
|
+
* Removes the group from the directory. Machines stop resolving it within about a minute;
|
|
1027
|
+
* files keep its gid.
|
|
1028
|
+
*
|
|
1029
|
+
* Requires `fleet:directory.manage`.
|
|
1030
|
+
* @summary Delete a group
|
|
1031
|
+
*/
|
|
1032
|
+
export const deleteGroup = async (groupId, options, fetchFn) => {
|
|
1033
|
+
const res = await (fetchFn ?? fetch)(getDeleteGroupUrl(groupId), {
|
|
1034
|
+
...options,
|
|
1035
|
+
method: "DELETE",
|
|
1036
|
+
});
|
|
1037
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1038
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
1039
|
+
return { data, status: res.status, headers: res.headers };
|
|
1040
|
+
};
|
|
1041
|
+
export const getListGroupMembersUrl = (groupId, params) => {
|
|
1042
|
+
const normalizedParams = new URLSearchParams();
|
|
1043
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
1044
|
+
if (value !== undefined) {
|
|
1045
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
const stringifiedParams = normalizedParams.toString();
|
|
1049
|
+
return stringifiedParams.length > 0
|
|
1050
|
+
? `https://fleet.leaflow.cloud/api/v1/groups/${encodeURIComponent(String(groupId))}/members?${stringifiedParams}`
|
|
1051
|
+
: `https://fleet.leaflow.cloud/api/v1/groups/${encodeURIComponent(String(groupId))}/members`;
|
|
1052
|
+
};
|
|
1053
|
+
/**
|
|
1054
|
+
* Returns the accounts in the group, ordered by username.
|
|
1055
|
+
* @summary List the members of a group
|
|
1056
|
+
*/
|
|
1057
|
+
export const listGroupMembers = async (groupId, params, options, fetchFn) => {
|
|
1058
|
+
const res = await (fetchFn ?? fetch)(getListGroupMembersUrl(groupId, params), {
|
|
1059
|
+
...options,
|
|
1060
|
+
method: "GET",
|
|
1061
|
+
});
|
|
1062
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1063
|
+
const data = body ? JSON.parse(body) : {};
|
|
1064
|
+
return { data, status: res.status, headers: res.headers };
|
|
1065
|
+
};
|
|
1066
|
+
export const getCreateGroupMemberUrl = (groupId) => {
|
|
1067
|
+
return `https://fleet.leaflow.cloud/api/v1/groups/${encodeURIComponent(String(groupId))}/members`;
|
|
1068
|
+
};
|
|
1069
|
+
/**
|
|
1070
|
+
* The account must be a member's. Fails with `GROUP_MEMBER_EXISTS` when the account is
|
|
1071
|
+
* already in the group.
|
|
1072
|
+
*
|
|
1073
|
+
* Requires `fleet:directory.manage`.
|
|
1074
|
+
* @summary Add an account to a group
|
|
1075
|
+
*/
|
|
1076
|
+
export const createGroupMember = async (groupId, createGroupMemberRequest, options, fetchFn) => {
|
|
1077
|
+
const getHeaders = (h) => {
|
|
1078
|
+
if (!h)
|
|
1079
|
+
return {};
|
|
1080
|
+
if (h instanceof Headers)
|
|
1081
|
+
return Object.fromEntries(h.entries());
|
|
1082
|
+
if (Symbol.iterator in h) {
|
|
1083
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1084
|
+
}
|
|
1085
|
+
const headers = {};
|
|
1086
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1087
|
+
if (value !== undefined)
|
|
1088
|
+
headers[name] = value;
|
|
1089
|
+
}
|
|
1090
|
+
return headers;
|
|
1091
|
+
};
|
|
1092
|
+
const res = await (fetchFn ?? fetch)(getCreateGroupMemberUrl(groupId), {
|
|
1093
|
+
...options,
|
|
1094
|
+
method: "POST",
|
|
1095
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1096
|
+
body: JSON.stringify(createGroupMemberRequest),
|
|
1097
|
+
});
|
|
1098
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1099
|
+
const data = body ? JSON.parse(body) : {};
|
|
1100
|
+
return { data, status: res.status, headers: res.headers };
|
|
1101
|
+
};
|
|
1102
|
+
export const getDeleteGroupMemberUrl = (groupId, accountId) => {
|
|
1103
|
+
return `https://fleet.leaflow.cloud/api/v1/groups/${encodeURIComponent(String(groupId))}/members/${encodeURIComponent(String(accountId))}`;
|
|
1104
|
+
};
|
|
1105
|
+
/**
|
|
1106
|
+
* Removing an account that is not in the group succeeds.
|
|
1107
|
+
*
|
|
1108
|
+
* Requires `fleet:directory.manage`.
|
|
1109
|
+
* @summary Remove an account from a group
|
|
1110
|
+
*/
|
|
1111
|
+
export const deleteGroupMember = async (groupId, accountId, options, fetchFn) => {
|
|
1112
|
+
const res = await (fetchFn ?? fetch)(getDeleteGroupMemberUrl(groupId, accountId), {
|
|
1113
|
+
...options,
|
|
1114
|
+
method: "DELETE",
|
|
1115
|
+
});
|
|
1116
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1117
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
1118
|
+
return { data, status: res.status, headers: res.headers };
|
|
1119
|
+
};
|
|
1120
|
+
export const getListSessionsUrl = (params) => {
|
|
1121
|
+
const normalizedParams = new URLSearchParams();
|
|
1122
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
1123
|
+
if (value !== undefined) {
|
|
1124
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
1125
|
+
}
|
|
1126
|
+
});
|
|
1127
|
+
const stringifiedParams = normalizedParams.toString();
|
|
1128
|
+
return stringifiedParams.length > 0
|
|
1129
|
+
? `https://fleet.leaflow.cloud/api/v1/sessions?${stringifiedParams}`
|
|
1130
|
+
: `https://fleet.leaflow.cloud/api/v1/sessions`;
|
|
1131
|
+
};
|
|
1132
|
+
/**
|
|
1133
|
+
* Returns the sessions of the current project's machines, newest first. Closed sessions are
|
|
1134
|
+
* omitted unless `include_closed` is true.
|
|
1135
|
+
* @summary List sessions
|
|
1136
|
+
*/
|
|
1137
|
+
export const listSessions = async (params, options, fetchFn) => {
|
|
1138
|
+
const res = await (fetchFn ?? fetch)(getListSessionsUrl(params), {
|
|
1139
|
+
...options,
|
|
1140
|
+
method: "GET",
|
|
1141
|
+
});
|
|
1142
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1143
|
+
const data = body ? JSON.parse(body) : {};
|
|
1144
|
+
return { data, status: res.status, headers: res.headers };
|
|
1145
|
+
};
|
|
1146
|
+
export const getCreateSessionUrl = () => {
|
|
1147
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions`;
|
|
1148
|
+
};
|
|
1149
|
+
/**
|
|
1150
|
+
* Opens a session for the caller on a machine, as the caller's account, and returns once it
|
|
1151
|
+
* is ready. With `desktop` the session has a desktop. Without, it is a terminal session: its
|
|
1152
|
+
* one terminal runs the caller's login shell from the start, every participant attaches to
|
|
1153
|
+
* that terminal, and the session ends when the shell exits; a caller who wants another
|
|
1154
|
+
* terminal opens another session. Either kind also offers programs, files, ports, sound,
|
|
1155
|
+
* devices, printers and privilege approvals. The account is created if the caller has none
|
|
1156
|
+
* yet. Requires `fleet:machines.login` on the machine.
|
|
1157
|
+
*
|
|
1158
|
+
* On a machine an account has at most one session with a desktop and at most 8 sessions in
|
|
1159
|
+
* all. Sessions without a desktop run side by side, such as one for a program and one for a
|
|
1160
|
+
* person; several participants can also share one session.
|
|
1161
|
+
*
|
|
1162
|
+
* Fails with:
|
|
1163
|
+
* - `MACHINE_OFFLINE` when the machine is not connected and does not connect again in time;
|
|
1164
|
+
* - `FEATURE_UNAVAILABLE` when the machine does not offer sessions, or with `desktop`,
|
|
1165
|
+
* desktops;
|
|
1166
|
+
* - `USER_HAS_DESKTOP_SESSION` with `desktop` when the account already has a session with a
|
|
1167
|
+
* desktop on the machine, which `metadata.sessionId` names; connect to it instead;
|
|
1168
|
+
* - `SESSION_LIMIT_REACHED` when the account already has 8 open sessions on the machine;
|
|
1169
|
+
* close one first;
|
|
1170
|
+
* - `USER_NOT_FOUND`, `USER_NOT_ALLOWED`, `ACCOUNT_EXPIRED` or `PAM_PERMISSION_DENIED` when
|
|
1171
|
+
* the machine refuses the account, such as while it has not received the account yet or a
|
|
1172
|
+
* local account uses its name; `PAM_PERMISSION_DENIED` carries the machine's message in
|
|
1173
|
+
* `metadata.pamMessage`;
|
|
1174
|
+
* - `SESSION_CONFLICT` with `desktop` when the account has a graphical session on the
|
|
1175
|
+
* machine that Fleet did not open;
|
|
1176
|
+
* - `DISPLAY_UNAVAILABLE` or `SESSION_START_FAILED` when the machine could not start it;
|
|
1177
|
+
* - `MACHINE_TIMEOUT` when the machine did not answer in time. The session may still open;
|
|
1178
|
+
* list the sessions before trying again.
|
|
1179
|
+
* @summary Open a session
|
|
1180
|
+
*/
|
|
1181
|
+
export const createSession = async (createSessionRequest, options, fetchFn) => {
|
|
1182
|
+
const getHeaders = (h) => {
|
|
1183
|
+
if (!h)
|
|
1184
|
+
return {};
|
|
1185
|
+
if (h instanceof Headers)
|
|
1186
|
+
return Object.fromEntries(h.entries());
|
|
1187
|
+
if (Symbol.iterator in h) {
|
|
1188
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1189
|
+
}
|
|
1190
|
+
const headers = {};
|
|
1191
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1192
|
+
if (value !== undefined)
|
|
1193
|
+
headers[name] = value;
|
|
1194
|
+
}
|
|
1195
|
+
return headers;
|
|
1196
|
+
};
|
|
1197
|
+
const res = await (fetchFn ?? fetch)(getCreateSessionUrl(), {
|
|
1198
|
+
...options,
|
|
1199
|
+
method: "POST",
|
|
1200
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1201
|
+
body: JSON.stringify(createSessionRequest),
|
|
1202
|
+
});
|
|
1203
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1204
|
+
const data = body ? JSON.parse(body) : {};
|
|
1205
|
+
return { data, status: res.status, headers: res.headers };
|
|
1206
|
+
};
|
|
1207
|
+
export const getGetSessionUrl = (sessionId) => {
|
|
1208
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}`;
|
|
1209
|
+
};
|
|
1210
|
+
/**
|
|
1211
|
+
* @summary Get a session
|
|
1212
|
+
*/
|
|
1213
|
+
export const getSession = async (sessionId, options, fetchFn) => {
|
|
1214
|
+
const res = await (fetchFn ?? fetch)(getGetSessionUrl(sessionId), {
|
|
1215
|
+
...options,
|
|
1216
|
+
method: "GET",
|
|
1217
|
+
});
|
|
1218
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1219
|
+
const data = body ? JSON.parse(body) : {};
|
|
1220
|
+
return { data, status: res.status, headers: res.headers };
|
|
1221
|
+
};
|
|
1222
|
+
export const getCloseSessionUrl = (sessionId) => {
|
|
1223
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}:close`;
|
|
1224
|
+
};
|
|
1225
|
+
/**
|
|
1226
|
+
* Ends the session in order: its applications are asked to exit and get a grace period
|
|
1227
|
+
* before the session is terminated. Returns once the session is closed. Closing a closed
|
|
1228
|
+
* session succeeds.
|
|
1229
|
+
*
|
|
1230
|
+
* The owner may close their own session; closing another member's requires
|
|
1231
|
+
* `fleet:sessions.manage`. Fails with `MACHINE_OFFLINE` or `MACHINE_TIMEOUT` as
|
|
1232
|
+
* for opening a session.
|
|
1233
|
+
* @summary Close a session
|
|
1234
|
+
*/
|
|
1235
|
+
export const closeSession = async (sessionId, options, fetchFn) => {
|
|
1236
|
+
const res = await (fetchFn ?? fetch)(getCloseSessionUrl(sessionId), {
|
|
1237
|
+
...options,
|
|
1238
|
+
method: "POST",
|
|
1239
|
+
});
|
|
1240
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1241
|
+
const data = body ? JSON.parse(body) : {};
|
|
1242
|
+
return { data, status: res.status, headers: res.headers };
|
|
1243
|
+
};
|
|
1244
|
+
export const getTerminateSessionUrl = (sessionId) => {
|
|
1245
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}:terminate`;
|
|
1246
|
+
};
|
|
1247
|
+
/**
|
|
1248
|
+
* Ends the session at once, killing every process in it. Returns once the session is
|
|
1249
|
+
* closed. Terminating a closed session succeeds.
|
|
1250
|
+
*
|
|
1251
|
+
* The owner may terminate their own session; terminating another member's requires
|
|
1252
|
+
* `fleet:sessions.manage`. Fails with `MACHINE_OFFLINE` or `MACHINE_TIMEOUT` as
|
|
1253
|
+
* for opening a session.
|
|
1254
|
+
* @summary Terminate a session
|
|
1255
|
+
*/
|
|
1256
|
+
export const terminateSession = async (sessionId, options, fetchFn) => {
|
|
1257
|
+
const res = await (fetchFn ?? fetch)(getTerminateSessionUrl(sessionId), {
|
|
1258
|
+
...options,
|
|
1259
|
+
method: "POST",
|
|
1260
|
+
});
|
|
1261
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1262
|
+
const data = body ? JSON.parse(body) : {};
|
|
1263
|
+
return { data, status: res.status, headers: res.headers };
|
|
1264
|
+
};
|
|
1265
|
+
export const getGetSessionRtcConfigurationUrl = (sessionId) => {
|
|
1266
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/rtc-configuration`;
|
|
1267
|
+
};
|
|
1268
|
+
/**
|
|
1269
|
+
* Returns the STUN and TURN servers for the PeerConnections the caller starts to the session,
|
|
1270
|
+
* with TURN credentials of its own, and the policy for using them. Ask again once
|
|
1271
|
+
* `expires_at` has passed; the credentials of a PeerConnection already relayed last longer.
|
|
1272
|
+
*
|
|
1273
|
+
* Requires that the caller may join the session, as for `create-participant`.
|
|
1274
|
+
*
|
|
1275
|
+
* Fails with:
|
|
1276
|
+
* - `SESSION_CLOSED` when the session has ended;
|
|
1277
|
+
* - `SESSION_ACCESS_DENIED` when the caller may not join the session.
|
|
1278
|
+
* @summary Get the ICE servers for a session
|
|
1279
|
+
*/
|
|
1280
|
+
export const getSessionRtcConfiguration = async (sessionId, options, fetchFn) => {
|
|
1281
|
+
const res = await (fetchFn ?? fetch)(getGetSessionRtcConfigurationUrl(sessionId), {
|
|
1282
|
+
...options,
|
|
1283
|
+
method: "GET",
|
|
1284
|
+
});
|
|
1285
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1286
|
+
const data = body ? JSON.parse(body) : {};
|
|
1287
|
+
return { data, status: res.status, headers: res.headers };
|
|
1288
|
+
};
|
|
1289
|
+
export const getCreateParticipantUrl = (sessionId) => {
|
|
1290
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants`;
|
|
1291
|
+
};
|
|
1292
|
+
/**
|
|
1293
|
+
* Admits one participant with the given public key to the session: signs its authorization,
|
|
1294
|
+
* has the session accept it, and starts its first PeerConnection with the offer. The answer
|
|
1295
|
+
* carries the participant, its authorization and the PeerConnection with the session's
|
|
1296
|
+
* answer. The participant lasts while it is renewed.
|
|
1297
|
+
*
|
|
1298
|
+
* Joining again with the public key of one of the caller's participants of the session that
|
|
1299
|
+
* has not ended, with the same `client_name`, `read_only` and `permissions`, returns that
|
|
1300
|
+
* participant with a new PeerConnection for the offer, and the session gains no second
|
|
1301
|
+
* participant: a request whose answer was lost, such as on an unreliable network, is sent
|
|
1302
|
+
* again as it was. Its earlier PeerConnection, whose answer the client never received, is
|
|
1303
|
+
* given up by the session once it fails.
|
|
1304
|
+
*
|
|
1305
|
+
* The owner of a session may operate it. Joining another member's session requires
|
|
1306
|
+
* `fleet:sessions.view`, which admits watching only, or
|
|
1307
|
+
* `fleet:sessions.control`, which also admits operating it. Each further capability
|
|
1308
|
+
* of the session — file transfer, the clipboard, terminals and programs, port forwarding,
|
|
1309
|
+
* devices and audio, printing, SSH agent forwarding, approving privilege requests and
|
|
1310
|
+
* reading logs — is granted only with its permission; a participant that may only watch gets
|
|
1311
|
+
* none of them. A request may ask for less: to watch only, or for some of the capabilities.
|
|
1312
|
+
*
|
|
1313
|
+
* Fails with the following, and then no participant was created:
|
|
1314
|
+
* - `SESSION_CLOSED` when the session has ended;
|
|
1315
|
+
* - `SESSION_ACCESS_DENIED` when the caller may not join the session;
|
|
1316
|
+
* - `OFFER_INVALID` when the offer is not an SDP offer that names a SHA-256 DTLS fingerprint;
|
|
1317
|
+
* - `SESSION_UNAVAILABLE` when the session's process is not connected and does not connect
|
|
1318
|
+
* again in time, or did not answer in time; try again after the error's `retry_delay`;
|
|
1319
|
+
* - `PARTICIPANT_LIMIT_REACHED` when the session has as many participants as it admits;
|
|
1320
|
+
* - `PARTICIPANT_REFUSED` when the session refused the participant;
|
|
1321
|
+
* - `PARTICIPANT_KEY_IN_USE` when the public key belongs to a participant of the session that
|
|
1322
|
+
* another user holds, or that was created with another `client_name`, `read_only` or
|
|
1323
|
+
* `permissions`; join with a new key;
|
|
1324
|
+
* - `PEER_CONNECTION_ABORTED` when the session gave up the PeerConnection; try again with a
|
|
1325
|
+
* new offer. The participant of a repeated request stays.
|
|
1326
|
+
* @summary Join a session
|
|
1327
|
+
*/
|
|
1328
|
+
export const createParticipant = async (sessionId, createParticipantRequest, options, fetchFn) => {
|
|
1329
|
+
const getHeaders = (h) => {
|
|
1330
|
+
if (!h)
|
|
1331
|
+
return {};
|
|
1332
|
+
if (h instanceof Headers)
|
|
1333
|
+
return Object.fromEntries(h.entries());
|
|
1334
|
+
if (Symbol.iterator in h) {
|
|
1335
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1336
|
+
}
|
|
1337
|
+
const headers = {};
|
|
1338
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1339
|
+
if (value !== undefined)
|
|
1340
|
+
headers[name] = value;
|
|
1341
|
+
}
|
|
1342
|
+
return headers;
|
|
1343
|
+
};
|
|
1344
|
+
const res = await (fetchFn ?? fetch)(getCreateParticipantUrl(sessionId), {
|
|
1345
|
+
...options,
|
|
1346
|
+
method: "POST",
|
|
1347
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1348
|
+
body: JSON.stringify(createParticipantRequest),
|
|
1349
|
+
});
|
|
1350
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1351
|
+
const data = body ? JSON.parse(body) : {};
|
|
1352
|
+
return { data, status: res.status, headers: res.headers };
|
|
1353
|
+
};
|
|
1354
|
+
export const getListSessionParticipantsUrl = (sessionId) => {
|
|
1355
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants`;
|
|
1356
|
+
};
|
|
1357
|
+
/**
|
|
1358
|
+
* Returns the participants of the session, in the order they joined.
|
|
1359
|
+
* @summary List the participants of a session
|
|
1360
|
+
*/
|
|
1361
|
+
export const listSessionParticipants = async (sessionId, options, fetchFn) => {
|
|
1362
|
+
const res = await (fetchFn ?? fetch)(getListSessionParticipantsUrl(sessionId), {
|
|
1363
|
+
...options,
|
|
1364
|
+
method: "GET",
|
|
1365
|
+
});
|
|
1366
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1367
|
+
const data = body ? JSON.parse(body) : {};
|
|
1368
|
+
return { data, status: res.status, headers: res.headers };
|
|
1369
|
+
};
|
|
1370
|
+
export const getRenewParticipantUrl = (sessionId, participantId) => {
|
|
1371
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}:renew`;
|
|
1372
|
+
};
|
|
1373
|
+
/**
|
|
1374
|
+
* Extends the participant's lease and returns renewed PeerAuthorizations for the
|
|
1375
|
+
* PeerConnections whose current ones the request presents. The service sends them to the
|
|
1376
|
+
* session as well, and the participant passes each one to the session over its PeerConnection
|
|
1377
|
+
* (`Packet.peer_authorization` of the transport protocol), so that the lease holds while
|
|
1378
|
+
* either path to the session is down. A
|
|
1379
|
+
* presented authorization that the service did not sign for this participant, or whose
|
|
1380
|
+
* PeerConnection has ended, is left out of the answer. When the participant's authorization
|
|
1381
|
+
* nears its end, the answer carries a renewed one, which the session already holds.
|
|
1382
|
+
*
|
|
1383
|
+
* Only the participant's user may renew it.
|
|
1384
|
+
*
|
|
1385
|
+
* Fails with:
|
|
1386
|
+
* - `PARTICIPANT_NOT_FOUND` when the participant has ended; create another;
|
|
1387
|
+
* - `PARTICIPANT_PERMISSION_REVOKED` when a permission the participant was created with has
|
|
1388
|
+
* been revoked from the caller; it has ended, and another can be created with the
|
|
1389
|
+
* permissions the caller holds now;
|
|
1390
|
+
* - `PROJECT_MEMBERSHIP_REQUIRED` when the caller is no longer a member of the project; the
|
|
1391
|
+
* participant has ended.
|
|
1392
|
+
* @summary Renew a participant
|
|
1393
|
+
*/
|
|
1394
|
+
export const renewParticipant = async (sessionId, participantId, renewParticipantRequest, options, fetchFn) => {
|
|
1395
|
+
const getHeaders = (h) => {
|
|
1396
|
+
if (!h)
|
|
1397
|
+
return {};
|
|
1398
|
+
if (h instanceof Headers)
|
|
1399
|
+
return Object.fromEntries(h.entries());
|
|
1400
|
+
if (Symbol.iterator in h) {
|
|
1401
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1402
|
+
}
|
|
1403
|
+
const headers = {};
|
|
1404
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1405
|
+
if (value !== undefined)
|
|
1406
|
+
headers[name] = value;
|
|
1407
|
+
}
|
|
1408
|
+
return headers;
|
|
1409
|
+
};
|
|
1410
|
+
const res = await (fetchFn ?? fetch)(getRenewParticipantUrl(sessionId, participantId), {
|
|
1411
|
+
...options,
|
|
1412
|
+
method: "POST",
|
|
1413
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1414
|
+
body: JSON.stringify(renewParticipantRequest),
|
|
1415
|
+
});
|
|
1416
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1417
|
+
const data = body ? JSON.parse(body) : {};
|
|
1418
|
+
return { data, status: res.status, headers: res.headers };
|
|
1419
|
+
};
|
|
1420
|
+
export const getPrepareParticipantMigrationUrl = (sessionId, participantId) => {
|
|
1421
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}:prepareMigration`;
|
|
1422
|
+
};
|
|
1423
|
+
/**
|
|
1424
|
+
* Passes the participant's checkpoint for the next epoch to the session and returns the
|
|
1425
|
+
* session's checkpoint for it: the `prepare` and `prepared` steps of `Migration` in
|
|
1426
|
+
* `leaflow/fleet/transport/v1/transport.proto`. Repeating the step returns the same answer.
|
|
1427
|
+
*
|
|
1428
|
+
* Only the participant's user may migrate it.
|
|
1429
|
+
*
|
|
1430
|
+
* Fails with:
|
|
1431
|
+
* - `PARTICIPANT_NOT_FOUND` when the participant has ended;
|
|
1432
|
+
* - `CHECKPOINT_INVALID` when the checkpoint is not a serialized `Checkpoint`;
|
|
1433
|
+
* - `SESSION_UNAVAILABLE` when the session's process is not connected and does not connect
|
|
1434
|
+
* again in time, or did not answer in time; try again after the error's `retry_delay`.
|
|
1435
|
+
* @summary Prepare a migration
|
|
1436
|
+
*/
|
|
1437
|
+
export const prepareParticipantMigration = async (sessionId, participantId, migrationStep, options, fetchFn) => {
|
|
1438
|
+
const getHeaders = (h) => {
|
|
1439
|
+
if (!h)
|
|
1440
|
+
return {};
|
|
1441
|
+
if (h instanceof Headers)
|
|
1442
|
+
return Object.fromEntries(h.entries());
|
|
1443
|
+
if (Symbol.iterator in h) {
|
|
1444
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1445
|
+
}
|
|
1446
|
+
const headers = {};
|
|
1447
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1448
|
+
if (value !== undefined)
|
|
1449
|
+
headers[name] = value;
|
|
1450
|
+
}
|
|
1451
|
+
return headers;
|
|
1452
|
+
};
|
|
1453
|
+
const res = await (fetchFn ?? fetch)(getPrepareParticipantMigrationUrl(sessionId, participantId), {
|
|
1454
|
+
...options,
|
|
1455
|
+
method: "POST",
|
|
1456
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1457
|
+
body: JSON.stringify(migrationStep),
|
|
1458
|
+
});
|
|
1459
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1460
|
+
const data = body ? JSON.parse(body) : {};
|
|
1461
|
+
return { data, status: res.status, headers: res.headers };
|
|
1462
|
+
};
|
|
1463
|
+
export const getCommitParticipantMigrationUrl = (sessionId, participantId) => {
|
|
1464
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}:commitMigration`;
|
|
1465
|
+
};
|
|
1466
|
+
/**
|
|
1467
|
+
* Commits the epoch the participant prepared and returns the session's checkpoint once it
|
|
1468
|
+
* committed it: the `commit` and `committed` steps of `Migration` in
|
|
1469
|
+
* `leaflow/fleet/transport/v1/transport.proto`. Repeating the step returns the same answer.
|
|
1470
|
+
*
|
|
1471
|
+
* Only the participant's user may migrate it.
|
|
1472
|
+
*
|
|
1473
|
+
* Fails with:
|
|
1474
|
+
* - `PARTICIPANT_NOT_FOUND` when the participant has ended;
|
|
1475
|
+
* - `CHECKPOINT_INVALID` when the checkpoint is not a serialized `Checkpoint`;
|
|
1476
|
+
* - `SESSION_UNAVAILABLE` when the session's process is not connected and does not connect
|
|
1477
|
+
* again in time, or did not answer in time; try again after the error's `retry_delay`.
|
|
1478
|
+
* @summary Commit a migration
|
|
1479
|
+
*/
|
|
1480
|
+
export const commitParticipantMigration = async (sessionId, participantId, migrationStep, options, fetchFn) => {
|
|
1481
|
+
const getHeaders = (h) => {
|
|
1482
|
+
if (!h)
|
|
1483
|
+
return {};
|
|
1484
|
+
if (h instanceof Headers)
|
|
1485
|
+
return Object.fromEntries(h.entries());
|
|
1486
|
+
if (Symbol.iterator in h) {
|
|
1487
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1488
|
+
}
|
|
1489
|
+
const headers = {};
|
|
1490
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1491
|
+
if (value !== undefined)
|
|
1492
|
+
headers[name] = value;
|
|
1493
|
+
}
|
|
1494
|
+
return headers;
|
|
1495
|
+
};
|
|
1496
|
+
const res = await (fetchFn ?? fetch)(getCommitParticipantMigrationUrl(sessionId, participantId), {
|
|
1497
|
+
...options,
|
|
1498
|
+
method: "POST",
|
|
1499
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1500
|
+
body: JSON.stringify(migrationStep),
|
|
1501
|
+
});
|
|
1502
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1503
|
+
const data = body ? JSON.parse(body) : {};
|
|
1504
|
+
return { data, status: res.status, headers: res.headers };
|
|
1505
|
+
};
|
|
1506
|
+
export const getCreatePeerConnectionUrl = (sessionId, participantId) => {
|
|
1507
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}/peer-connections`;
|
|
1508
|
+
};
|
|
1509
|
+
/**
|
|
1510
|
+
* Starts another PeerConnection of the participant with the offer, such as after a path
|
|
1511
|
+
* failed, and returns the session's answer, its ICE candidates and the signed
|
|
1512
|
+
* PeerAuthorization. Move the participant's connection to it with
|
|
1513
|
+
* `prepare-participant-migration` and `commit-participant-migration`.
|
|
1514
|
+
*
|
|
1515
|
+
* Only the participant's user may start one.
|
|
1516
|
+
*
|
|
1517
|
+
* Fails with:
|
|
1518
|
+
* - `PARTICIPANT_NOT_FOUND` when the participant has ended;
|
|
1519
|
+
* - `OFFER_INVALID` when the offer is not an SDP offer that names a SHA-256 DTLS fingerprint;
|
|
1520
|
+
* - `RATE_LIMIT_EXCEEDED` when the participant started too many PeerConnections in the
|
|
1521
|
+
* last minute; try again after the error's `retry_delay`;
|
|
1522
|
+
* - `SESSION_UNAVAILABLE` when the session's process is not connected and does not connect
|
|
1523
|
+
* again in time, or did not answer in time; try again after the error's `retry_delay`;
|
|
1524
|
+
* - `PEER_CONNECTION_ABORTED` when the session gave up the PeerConnection; start another.
|
|
1525
|
+
* @summary Start a PeerConnection
|
|
1526
|
+
*/
|
|
1527
|
+
export const createPeerConnection = async (sessionId, participantId, createPeerConnectionRequest, options, fetchFn) => {
|
|
1528
|
+
const getHeaders = (h) => {
|
|
1529
|
+
if (!h)
|
|
1530
|
+
return {};
|
|
1531
|
+
if (h instanceof Headers)
|
|
1532
|
+
return Object.fromEntries(h.entries());
|
|
1533
|
+
if (Symbol.iterator in h) {
|
|
1534
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1535
|
+
}
|
|
1536
|
+
const headers = {};
|
|
1537
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1538
|
+
if (value !== undefined)
|
|
1539
|
+
headers[name] = value;
|
|
1540
|
+
}
|
|
1541
|
+
return headers;
|
|
1542
|
+
};
|
|
1543
|
+
const res = await (fetchFn ?? fetch)(getCreatePeerConnectionUrl(sessionId, participantId), {
|
|
1544
|
+
...options,
|
|
1545
|
+
method: "POST",
|
|
1546
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1547
|
+
body: JSON.stringify(createPeerConnectionRequest),
|
|
1548
|
+
});
|
|
1549
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1550
|
+
const data = body ? JSON.parse(body) : {};
|
|
1551
|
+
return { data, status: res.status, headers: res.headers };
|
|
1552
|
+
};
|
|
1553
|
+
export const getDeletePeerConnectionUrl = (sessionId, participantId, peerConnectionId) => {
|
|
1554
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}/peer-connections/${encodeURIComponent(String(peerConnectionId))}`;
|
|
1555
|
+
};
|
|
1556
|
+
/**
|
|
1557
|
+
* Tells the session to give up the PeerConnection and close it. Abandoning a PeerConnection
|
|
1558
|
+
* that has ended succeeds.
|
|
1559
|
+
*
|
|
1560
|
+
* Only the participant's user may abandon it.
|
|
1561
|
+
*
|
|
1562
|
+
* Fails with `PARTICIPANT_NOT_FOUND` when the participant has ended.
|
|
1563
|
+
* @summary Abandon a PeerConnection
|
|
1564
|
+
*/
|
|
1565
|
+
export const deletePeerConnection = async (sessionId, participantId, peerConnectionId, options, fetchFn) => {
|
|
1566
|
+
const res = await (fetchFn ?? fetch)(getDeletePeerConnectionUrl(sessionId, participantId, peerConnectionId), {
|
|
1567
|
+
...options,
|
|
1568
|
+
method: "DELETE",
|
|
1569
|
+
});
|
|
1570
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1571
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
1572
|
+
return { data, status: res.status, headers: res.headers };
|
|
1573
|
+
};
|
|
1574
|
+
export const getCreatePeerConnectionCandidatesUrl = (sessionId, participantId, peerConnectionId) => {
|
|
1575
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}/peer-connections/${encodeURIComponent(String(peerConnectionId))}/candidates`;
|
|
1576
|
+
};
|
|
1577
|
+
/**
|
|
1578
|
+
* Passes the ICE candidates the participant gathered after its offer to the session, and with
|
|
1579
|
+
* `end_of_candidates`, that it has gathered all (RFC 8838). The session ignores those of a
|
|
1580
|
+
* PeerConnection that has ended.
|
|
1581
|
+
*
|
|
1582
|
+
* Only the participant's user may add them.
|
|
1583
|
+
*
|
|
1584
|
+
* Fails with:
|
|
1585
|
+
* - `PARTICIPANT_NOT_FOUND` when the participant has ended;
|
|
1586
|
+
* - `SESSION_UNAVAILABLE` when the session's process is not connected and does not connect
|
|
1587
|
+
* again in time; try again after the error's `retry_delay`.
|
|
1588
|
+
* @summary Add ICE candidates to a PeerConnection
|
|
1589
|
+
*/
|
|
1590
|
+
export const createPeerConnectionCandidates = async (sessionId, participantId, peerConnectionId, createPeerConnectionCandidatesRequest, options, fetchFn) => {
|
|
1591
|
+
const getHeaders = (h) => {
|
|
1592
|
+
if (!h)
|
|
1593
|
+
return {};
|
|
1594
|
+
if (h instanceof Headers)
|
|
1595
|
+
return Object.fromEntries(h.entries());
|
|
1596
|
+
if (Symbol.iterator in h) {
|
|
1597
|
+
return Object.fromEntries(Array.from(h, (entry) => Array.from(entry)));
|
|
1598
|
+
}
|
|
1599
|
+
const headers = {};
|
|
1600
|
+
for (const [name, value] of Object.entries(h)) {
|
|
1601
|
+
if (value !== undefined)
|
|
1602
|
+
headers[name] = value;
|
|
1603
|
+
}
|
|
1604
|
+
return headers;
|
|
1605
|
+
};
|
|
1606
|
+
const res = await (fetchFn ?? fetch)(getCreatePeerConnectionCandidatesUrl(sessionId, participantId, peerConnectionId), {
|
|
1607
|
+
...options,
|
|
1608
|
+
method: "POST",
|
|
1609
|
+
headers: { "Content-Type": "application/json", ...getHeaders(options?.headers) },
|
|
1610
|
+
body: JSON.stringify(createPeerConnectionCandidatesRequest),
|
|
1611
|
+
});
|
|
1612
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1613
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
1614
|
+
return {
|
|
1615
|
+
data,
|
|
1616
|
+
status: res.status,
|
|
1617
|
+
headers: res.headers,
|
|
1618
|
+
};
|
|
1619
|
+
};
|
|
1620
|
+
export const getGetParticipantUrl = (sessionId, participantId) => {
|
|
1621
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}`;
|
|
1622
|
+
};
|
|
1623
|
+
/**
|
|
1624
|
+
* Returns a participant of the session.
|
|
1625
|
+
* @summary Get a participant of a session
|
|
1626
|
+
*/
|
|
1627
|
+
export const getParticipant = async (sessionId, participantId, options, fetchFn) => {
|
|
1628
|
+
const res = await (fetchFn ?? fetch)(getGetParticipantUrl(sessionId, participantId), {
|
|
1629
|
+
...options,
|
|
1630
|
+
method: "GET",
|
|
1631
|
+
});
|
|
1632
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1633
|
+
const data = body ? JSON.parse(body) : {};
|
|
1634
|
+
return { data, status: res.status, headers: res.headers };
|
|
1635
|
+
};
|
|
1636
|
+
export const getDeleteParticipantUrl = (sessionId, participantId) => {
|
|
1637
|
+
return `https://fleet.leaflow.cloud/api/v1/sessions/${encodeURIComponent(String(sessionId))}/participants/${encodeURIComponent(String(participantId))}`;
|
|
1638
|
+
};
|
|
1639
|
+
/**
|
|
1640
|
+
* Ends the participant: the session detaches it and closes its PeerConnections, and the
|
|
1641
|
+
* session goes on. A participant leaves this way; others are disconnected this way.
|
|
1642
|
+
*
|
|
1643
|
+
* The participant's user and the owner of the session may end it; otherwise this
|
|
1644
|
+
* requires `fleet:sessions.manage`.
|
|
1645
|
+
* @summary End a participant
|
|
1646
|
+
*/
|
|
1647
|
+
export const deleteParticipant = async (sessionId, participantId, options, fetchFn) => {
|
|
1648
|
+
const res = await (fetchFn ?? fetch)(getDeleteParticipantUrl(sessionId, participantId), {
|
|
1649
|
+
...options,
|
|
1650
|
+
method: "DELETE",
|
|
1651
|
+
});
|
|
1652
|
+
const body = [204, 205, 304].includes(res.status) ? null : await res.text();
|
|
1653
|
+
const data = body ? JSON.parse(body) : undefined;
|
|
1654
|
+
return { data, status: res.status, headers: res.headers };
|
|
1655
|
+
};
|